Suppose I have 10x10 matrix with the following data:
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 _ 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70
71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90
91 92 93 94 95 96 97 98 99 100
My position is in [4][4]
. How can I list the diagonal values from this position?
For example, the expected outcome would be:
[56, 67, 78, 89, 100, 1, 12, 23, 34]
[54, 63, 72, 81, 9, 18, 27, 36]
def next?(index, row, size)
(((row + index) % size) + 1 ) % size
end
(1...chess_size).each do |l|
next_el, curr_el = next?(l, row, chess_size), (row + l) % chess_size
# this gets me the first diagnonal. Note that it prints out wrong value
tmp[0] << chess[curr_el][curr_el]
# this gets me the values from current row below to up
tmp[1] << chess[(row + l) % chess_size][row]
tmp[2] << chess[-l][l]
tmp[3] << chess[row][(row + l) % chess_size]
end
Our matrix will always have the same number of rows and columns.
This is a solution to the Hackerrank Queen's attack problem.
Code
def count_moves(n, obs, qrow, qcol)
qdiff = qrow-qcol
qsum = qrow+qcol
l = u = -1
r = d = n
ul = qdiff >= 0 ? qrow-qcol-1 : -1
dr = qdiff >= 0 ? n : qrow+n-qcol
ur = qsum < n ? -1 : qrow-n+qcol
dl = qsum < n ? qrow+qcol+1 : n
obs.uniq.each do |i,j|
case i <=> qrow
when -1 # up
case j <=> qcol
when -1 # up-left
ul = [ul,i].max
when 0 # up same col
u = [u,i].max
when 1 # up-right
ur = [ur,i].max
end
when 0 # same row
j < qcol ? (l = [l,j].max) : r = [r,j].min
else # down
case j <=> qcol
when -1 # down-left
dl = [dl,i].min
when 0 # down same col
d = [d,i].min
when 1 # down-right
dr = [dr,i].min
end
end
end
r + dl + d + dr - l - ul -u - ur - 8
end
Example
Suppose the chess board has 9
rows and columns, with the queen's location shown by the character q
and each obstruction shown with the letter o
. All other locations are represented by the letter x
. We see that the queen has 16
possible moves (7
up and down, 6
left and right, 1
on the up-left to down-right diagonal and 2
on the up-right to down-left diagonal.
arr = [
%w| x x x x x x x x x |, # 0
%w| o x x x x x x x x |, # 1
%w| x o x x x x x x x |, # 2
%w| x x o x x x x x o |, # 3
%w| x x x o x x x x x |, # 4
%w| x x x x x x o x x |, # 5
%w| o o x x x q x x x |, # 6
%w| x x x x x x o x x |, # 7
%w| x x x x x o x x x | # 8
# 0 1 2 3 4 5 6 7 8
]
qrow = qcol = nil
obs = []
n = arr.size
arr.each_with_index do |a,i|
a.each_with_index do |c,j|
case c
when 'o'
obs << [i,j]
when 'q'
qrow=i
qcol=j
end
end
end
qrow
#=> 6
qcol
#=> 5
obs
#=> [[1, 0], [2, 1], [3, 2], [3, 8], [4, 3], [5, 6], [6, 0], [6, 1], [7, 6], [8, 5]]
count_moves(n, obs, qrow, qcol)
#=> 16
Explanation
l
is the largest column index of an obstruction in the queen's row that is less than the queen's column index;r
is the smalles column index of an obstruction in the queens that is greater than the queen's column index;u
is the largest largest row index of an obstruction in the queen's column that is less than the queen's row index;d
is the smallest row index of an obstruction in the queen's column that is greater than the queen's row index;ul
is the greatest row index of an obstruction on the queen's top-left to bottom-right diagonal that is less than the queen's row index;dr
is the smallest row index of an obstruction on the queen's top-left to bottom-right diagonal that is greater than the queen's row index;ur
is the greatest row index of an obstruction on the queen's top-right to bottom-left diagonal that is less than the queen's row index; anddl
is the smallest row index of an obstruction on the queen's top-right to bottom-left diagonal that is greater than the queen's row index.For the example above, before obstructions are taken into account, these variables are set to the following values.
l = 0
r = 9
ul = 0
u = -1
ur = 2
dl = 9
d = 9
dr = 9
Note that if the queen has row and column indices qrow
and qcol
,
i - j = qrow - qcol
for all locations [i, j]
on the queen's top-left to bottom- right diagonal; andi + j = grow + gcol
for all locations [i, j]
on the queen's top-right to bottom- left diagonalWe then loop through all (unique) obstructions, determining, for each, whether it is in the queen's row, queen's column, or one of the queen's diagonals and then replaces the value of the applicable variable with it's row or column index if it is "closer" to the queen than the previously-closest location.
If, for example, the obstruction is in the queen's row and its column index j
is less than the queen's column index, the following calculation is made:
l = [l, j].max
Similarly, if the obstruction is on the queen's top-left to bottom-right diagonal and its row index i
is less than the queen's row index, the calculation would be:
ul = [ul, i].max
After all obstructions from the above example have been considered the variables have the following values.
l #=> 1
r #=> 9
ul #=> 4
u #=> -1
ur #=> 5
dl #=> 9
d #=> 8
dr #=> 7
Lastly, we compute the total number of squares to which the queen may move.
qcol - l - 1 + # left
r - qcol - 1 + # right
u - qrow - 1 + # up
grow - d - 1 + # down
ul - qrow - 1 + # up-left
ur - qrow - 1 + # up-right
qrow - dl - 1 + # down-left
qrow - dr - 1 # down-right
which simplifies to
r + dl + d + dr - l - ul -u - ur - 8
#=> 9 + 9 + 8 + 7 - 1 - 4 + 1 - 5 - 8 => 16