kat*_*987 1 ruby arrays multidimensional-array
我正在 Ruby Connect 4 游戏中测试对角获胜。我一直在使用硬编码的二维数组进行测试:
grid_array = [
["B", ".", ".", ".", ".", ".", ".", "."],
[".", "B", ".", ".", ".", ".", ".", "."],
[".", ".", "B", ".", ".", ".", ".", "."],
[".", ".", ".", "B", ".", ".", ".", "."],
[".", ".", ".", "X", "M", ".", ".", "."],
[".", ".", ".", ".", "X", "M", ".", "."],
[".", ".", ".", ".", ".", "X", "M", "."],
[".", ".", ".", ".", ".", ".", "X", "M"]
]
Run Code Online (Sandbox Code Playgroud)
该方法的内部循环工作正常(正确识别'M'或单独为获胜者,但例如,'B'当尝试将对角线检查跨列或向上移动到外循环以获取获胜值时,我陷入困境。'X'
def nw_diagonal_win (playing_board)
row = 7
while row < playing_board.size && row >= 0
row = 7
column = 7
piece_count = 0
while (row < playing_board.size && column < playing_board[row].size && column >= 0)
if playing_board[row][column] == 'M'
piece_count += 1
if piece_count == 4
puts "Player is the winner in a diagonal!"
end
puts piece_count.inspect
else
piece_count = 0
puts "No winner."
end
row += 1
column += 1
end
row -= 1
end
end
Run Code Online (Sandbox Code Playgroud)
编辑添加:Connect 4 中的“获胜者”设置 4 个相邻的块(水平、垂直或对角线)。'X'在我的游戏中,这由和表示'0'。棋子从网格中一列的顶部“掉落”,并落到该列中最底部的可用空间。棋子可以堆叠成一列,但不能“漂浮”在棋盘中间。对角线可以从左上到右下或从右上到左下。仅当棋子在网格内不间断(没有环绕)时才会获胜。
想象一下井字游戏的更大版本,其中必须首先在底行进行移动,然后可以在上面的行中进行移动,就像盒子一样堆叠。连续四次(水平、垂直或对角\/)获胜。
为了回应史蒂夫的回答建议,如下:
def top_left_diagonal (playing_board, player_piece)
row = 0
while row < playing_board.size - 3
piece_count = 0
column = 0
while column < playing_board[row].size - 3 && playing_board[row][column] == player_piece
if (playing_board[row][column] == playing_board[row + piece_count][column + piece_count])
piece_count += 1
else
piece_count = 0
end
column += 1
end
if piece_count == 4
puts "Diagonal winner!"
end
row += 1
end
end
Run Code Online (Sandbox Code Playgroud)
假设我们有
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"]]
Run Code Online (Sandbox Code Playgroud)
确实,这只是 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
Run Code Online (Sandbox Code Playgroud)
如果连续w有四个,则此方法返回,如果连续有四个,则返回。wbbnil
因为arr = grid我们发现没有一行连续包含四个'b'' 或'w'' 。
four_in_a_row_by_row(grid)
#=> nil
Run Code Online (Sandbox Code Playgroud)
请注意,此方法不要求arr.size == grid.size或 的所有元素arr具有相同的大小。它只是检查是否有任何元素有四个'w'或四个'b'连续。这在以后会有重要意义。
例如,传递到块的最后一个元素arr如下。
row = ["b", "w", "b", "b", "w", "b"]
Run Code Online (Sandbox Code Playgroud)
然后我们计算
enum0 = row.each_cons(4)
#=> #<Enumerator: ["b", "w", "b", "b", "w", "b"]:each_cons(4)>
Run Code Online (Sandbox Code Playgroud)
和
enum1 = enum0.find
#=> #<Enumerator: #<Enumerator: ["b", "w", "b", "b", "w", "b"]:each_cons(4)>:find>
Run Code Online (Sandbox Code Playgroud)
enum1可以被认为是一个复合枚举器,尽管 Ruby 并没有这样定义。请参阅Enumerable#each_cons和Enumerable#find。
我们可以将此枚举器转换为数组以查看将传递到块的元素。
enum1.to_a
#=> [["b", "w", "b", "b"],
# ["w", "b", "b", "w"],
# ["b", "b", "w", "b"]]
Run Code Online (Sandbox Code Playgroud)
第一个元素被传递到块并进行以下计算。
a = enum1.next
u = a.uniq
u.size == 1
Run Code Online (Sandbox Code Playgroud)
因此我们不需要计算a.first != '.'. 的剩余两个元素enum1被传递到块并为每个元素进行计算,表明一行中或最后一行nil中没有四个元素。'w''b'
我们快完成了!
“等等”,你说,我们只检查了行!仍然有柱子和所有的对角线!敬请关注...
检查列
这个非常简单。
four_in_a_row_by_row(grid.transpose)
#=> nil
Run Code Online (Sandbox Code Playgroud)
这里
grid.transpose
#=> [[".", ".", ".", "b", "w", "b"],
# [".", ".", ".", ".", "w", "w"],
# [".", ".", ".", "w", ".", "b"],
# [".", "w", "w", ".", "w", "b"],
# [".", "w", "b", "b", "b", "w"],
# [".", ".", ".", ".", "b", "b"]]
Run Code Online (Sandbox Code Playgroud)
检查对角线(从左上到右下)
这里我们需要做的就是构造一个arr包含对角线的数组,然后应用four_in_a_row(arr)。首先确定包含第一列中长度或更长的元素的对角线4。包括以下对角线
[grid[0][0], grid[1][1], grid[2][2], grid[3][3], grid[4][4],grid[5][5]]
[grid[1][0], grid[2][1], grid[3][2], grid[4][3], grid[5][4]]
[grid[2][0], grid[3][1], grid[4][2], grid[5][3]]
Run Code Online (Sandbox Code Playgroud)
没有必要考虑包含第一列中的元素的剩余对角线,因为它们包含的4元素少于:
[grid[3][0], grid[4][1], grid[5][2]]
[grid[4][0], grid[5][1]]
[grid[5][0]]
Run Code Online (Sandbox Code Playgroud)
我们可以如下获得前三个对角线。
(0..grid.size-4).map { |i| (0..grid.size-1-i).map { |j| grid[i+j][j] } }
#=> [[".", ".", ".", ".", "b", "b"],
# [".", ".", "w", "w", "w"],
# [".", ".", ".", "b"]]
Run Code Online (Sandbox Code Playgroud)
同样,确定包含第一行中的元素(除 之外)的对角线grid[0][0],这些元素的长度4或更大。这些是对角线
[grid[0][1], grid[1][2], grid[2][3], grid[3][4], grid[4][5]]
[grid[0][2], grid[1][3], grid[2][4], grid[3][5]]
Run Code Online (Sandbox Code Playgroud)
包含第一行中的元素(除 之外grid[0][0])的其余对角线包含少于4元素。我们按如下方式获得这些对角线。
(1..grid.first.size-4).map do |j|
(0..grid.size-j-1).map { |i| grid[i][j+i] }
end
#=> [[".", ".", "w", "b", "b"],
# [".", "w", "b", "."]]
Run Code Online (Sandbox Code Playgroud)
因此,我们可以获得所有对角线的数组,如下所示。
def diagonals(grid)
(0..grid.size-4).map do |i|
(0..grid.size-1-i).map { |j| grid[i+j][j] }
end.concat((1..grid.first.size-4).map do |j|
(0..grid.size-j-1).map { |i| grid[i][j+i] }
end)
end
Run Code Online (Sandbox Code Playgroud)
arr = diagonals(grid)
#=> [[".", ".", ".", ".", "b", "b"],
# [".", ".", "w", "w", "w"],
# [".", ".", ".", "b"],
# [".", ".", "w", "b", "b"],
# [".", "w", "b", "."]]
Run Code Online (Sandbox Code Playgroud)
我们看到没有一条对角线包含连续的四个对角线。
four_in_a_row_by_row(arr)
#=> nil
Run Code Online (Sandbox Code Playgroud)
检查对角线(左下角到右上角)
grid我们可以进行与计算对角线相同的推理,但由于这里计算效率并不重要,因此有一种更简单的方法:计算“旋转” 90度获得的数组的对角线。
def rotate90(grid)
ncols = grid.first.size
grid.each_index.with_object([]) do |i,a|
a << ncols.times.map { |j| grid[j][ncols-1-i] }
end
end
Run Code Online (Sandbox Code Playgroud)
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"]]
Run Code Online (Sandbox Code Playgroud)
我们看到没有任何对角线包含连续的四个对角线。
four_in_a_row_by_row(arr1)
#=> "w"
Run Code Online (Sandbox Code Playgroud)
把它们放在一起
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"
Run Code Online (Sandbox Code Playgroud)
的替代计算four_in_a_row_by_row
或者可以写four_in_a_row_by_row如下。
def four_in_a_row_by_row(arr)
row = arr.find { |row| four_in_a_row(row) }
row.nil? ? nil : four_in_a_row(row)
end
Run Code Online (Sandbox Code Playgroud)
def four_in_a_row(row)
(0..row.size-5).find { |j| row[j,4].uniq.size == 1 && row[j] != '.' }
end
Run Code Online (Sandbox Code Playgroud)
four_in_a_row_by_row(grid)
#=> nil
Run Code Online (Sandbox Code Playgroud)
如果愿意,row.nil? ? nil : four_in_a_row(row)可以替换为
four_in_a_row(row) unless row.nil?
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3431 次 |
| 最近记录: |