Предположим, у нас есть
grid = [
%w| . . . . . . |,
%w| . . . w w . |,
%w| . . . w b . |,
%w| b . w . b . |,
%w| w w . w b b |,
%w| b w b b w b |
]
#=> [[".", ".", ".", ".", ".", "."],
# [".", ".", ".", "w", "w", "."],
# [".", ".", ".", "w", "b", "."],
# ["b", ".", "w", ".", "b", "."],
# ["w", "w", ".", "w", "b", "b"],
# ["b", "w", "b", "b", "w", "b"]]
Правда, это всего лишь 6x6, но решение ничем не отличается.
Во-первых, так как массив маленький, нам не о чем беспокоитьсяо вычислительной эффективности, поэтому мы можем сосредоточиться на эффективности кода.
Давайте сначала проверим, есть ли четыре в строке в каждой строке.
Проверка строк
def four_in_a_row_by_row(arr)
arr.each do |row|
a = row.each_cons(4).find { |a| a.uniq.size == 1 && a.first != '.' }
return a.first unless a.nil?
end
nil
end
Этот метод возвращает w
, если в строке четыре w
, b
, если их четыреb
в строке, иначе nil
.
Обратите внимание, что этот метод не требует, чтобы arr.size == grid.size
или чтобы все элементы arr
были одинакового размера.Он просто проверяет, имеет ли какой-либо элемент четыре 'w'
или четыре 'b'
подряд.Это будет иметь значение позже.
Последний элемент arr
, переданный, например, в блок, следующий:
row = ["b", "w", "b", "b", "w", "b"]
Затем мы вычисляем
enum0 = row.each_cons(4)
#=> #<Enumerator: ["b", "w", "b", "b", "w", "b"]:each_cons(4)>
и
enum1 = enum0.find
#=> #<Enumerator: #<Enumerator: ["b", "w", "b", "b", "w", "b"]:each_cons(4)>:find>
enum1
можно рассматривать как составной перечислитель, хотя Ruby не определяет его так.
Мы можем преобразовать этот перечислитель вмассив для просмотра элементов, которые будут переданы в блок.
enum1.to_a
#=> [["b", "w", "b", "b"], ["w", "b", "b", "w"], ["b", "b", "w", "b"]]
См. Enumerable # each_cons .
Первый элемент передается в блок иследующие вычисления сделаны.
a = enum1.next
u = a.uniq
u.size == 1
Поэтому нам не нужно вычислять a.first != '.'
.Оставшиеся два элемента enum1
передаются в блок, и для каждого вычисляется nil
, что указывает на то, что в последнем ряду нет ни четырех 'w'
, ни 'b'
.
Мы почти закончили!
"Подождите", говорите, мы только проверили строки!Есть еще колонны и все диагонали!Оставайтесь с нами ...
Проверьте столбцы
Это очень просто.
four_in_a_row_by_row(grid.transpose)
#=> nil
Проверьте диагонали (верхслева направо)
Здесь все, что нам нужно сделать, - это создать массив arr
, содержащий диагонали, а затем применить four_in_a_row(arr)
.Сначала определите диагонали, которые включают элементы в первом столбце, которые имеют длину 4
или больше:
(0..grid.size-4).map { |i| (0..grid.size-1-i).map { |j| grid[i+j][j] } }
#=> [[".", ".", ".", ".", "b", "b"], [".", ".", "w", "w", "w"], [".", ".", ".", "b"]]
Аналогично, определите диагонали, которые включают элементы в первом ряду, отличные от [0, 0]
, которые имеют длину 4
или больше:
(1..grid.first.size-4).map { |j| (0..grid.size-j-1).map { |i| grid[i][j+i] } }
#=> [[".", ".", "w", "b", "b"], [".", "w", "b", "."]]
def diagonals(grid)
(0..grid.size-4).map { |i| (0..grid.size-1-i).map { |j| grid[i+j][j] } }.
concat((1..grid.first.size-4).map { |j| (0..grid.size-j-1).map { |i| grid[i][j+i] } })
end
arr = diagonals(grid)
#=> [[".", ".", ".", ".", "b", "b"], [".", ".", "w", "w", "w"], [".", ".", ".", "b"],
# [".", ".", "w", "b", "b"], [".", "w", "b", "."]]
four_in_a_row_by_row(arr)
#=> nil
Проверьте андиагоналы (с левого на верхний правый угол)
Мы могли бы пройти через те же рассуждениякак и при вычислении диагоналей, но поскольку эффективность вычислений здесь не важна, есть более простой способ: вычислить диагонали массива, полученные «вращением» grid
90 градусов.
def rotate90(grid)
ncols = grid.first.size
grid.each_index.with_object([]) { |i,a| a << ncols.times.map { |j| grid[j][ncols-1-i] } }
end
arr = rotate90(grid)
#=> [[".", ".", ".", ".", "b", "b"],
# [".", "w", "b", "b", "b", "w"],
# [".", "w", "w", ".", "w", "b"],
# [".", ".", ".", "w", ".", "b"],
# [".", ".", ".", ".", "w", "w"],
# [".", ".", ".", "b", "w", "b"]]
arr1 = diagonals(arr)
#=> [[".", "w", "w", "w", "w", "b"], [".", "w", ".", ".", "w"],
# [".", ".", ".", "b"], [".", "b", ".", ".", "w"], [".", "b", "w", "b"]]
four_in_a_row_by_row(arr1)
#=> "w"
Собираем все вместе
def four_in_a_row(grid)
four_in_a_row_by_row(grid) ||
four_in_a_row_by_row(grid.transpose) ||
four_in_a_row_by_row(diagonals(grid)) ||
four_in_a_row_by_row(diagonals(rotate90(grid)))
end
four_in_a_row_by_row(grid)
#=> "w"