如何解决为什么这个函数会产生混乱的结果而不是计算 Conway's Game Of Life?
我正在用 Ruby 编写康威的游戏人生。该游戏基于一个二维布尔数组,其中 true 代表一个活细胞,而 false 代表一个死细胞。 (例如
arr = [
[false,false,false],[false,true,false]
]
将用于制作滑翔机) 按照规则,相信大多数人都知道,它应该创造一个向右和底部反复改革的格局。但是,当我运行此代码时,它会产生一个爆炸的混乱模式。 这是我的主要函数,它计算新的棋盘状态:
def iterate(arr)
arr = arr.dup
new_arr = arr
y_counter = 0
arr.each do |elem|
x_counter = 0
elem.each do
count = 0
neighbors = [
(arr[y_counter-1] || [false,false])[x_counter-1],(arr[y_counter-1] || [false,false])[x_counter],(arr[y_counter-1]|| [false,false])[x_counter+1],(arr[y_counter]|| [false,(arr[y_counter+1]|| [false,]
neighbors.each do |elem|
count += 1 if elem
end
new_arr[y_counter][x_counter] = (count == 2) || (count == 3 && arr[y_counter][x_counter])
x_counter+=1
end
y_counter+=1
end
new_arr
end
为什么它不起作用,我该怎么做才能解决它?
解决方法
考虑使用几种方法编写代码来执行不同的任务。首先,我们需要在终端中显示网格的图片。我们可能会这样做。
ALIVE = "?"
DEAD = "?"
def display_grid(grid)
last_col = grid.first.size
system("clear")
grid.each_index do |i|
puts (0..last_col).map { |j| grid[i][j] ? ALIVE : DEAD }.join
end
end
display_grid(grid)
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
system("clear")
在 OS X 和 Linux 中清除终端。 system("cls")
在 Windows 中也是如此。我知道 Ruby v2.7 引入了一种跨平台的方式来做到这一点:
require 'io/console'
$stdout.clear_screen # or STDOUT.clear_screen
接下来,对于网格中的每个单元格,我们需要计算其存活的相邻单元格的数量。
def neighbors_alive(grid,(row,col))
rows = ([row-1,0].max..[row+1,arr.size-1].min).to_a
cols = ([col-1,0].max..[col+1,arr.first.size-1].min).to_a
neighbors = rows.product(cols) - [cell]
neighbors.count { |row,col| grid[row][col] }
end
例如:
neighbors_alive(grid,[0,0]) #=> 0
neighbors_alive(grid,[1,1]) #=> 0
neighbors_alive(grid,[2,2]) #=> 1
neighbors_alive(grid,[3,3]) #=> 5
neighbors_alive(grid,[4,4]) #=> 2
neighbors_alive(grid,[5,5]) #=> 1
neighbors_alive(grid,[6,6]) #=> 0
对单元格[4,3]
的计算如下,该单元格以以下3x3子数组为中心:
[false,false,true],# ???
[true,true,# ???
[false,false]] # ???
所以我们希望这个数字是 3
。
row,col = [4,3]
row
#=> 4
col
#=> 3
rows = ([row-1,arr.size-1].min).to_a
#=> [3,4,5]
cols = ([col-1,arr.first.size-1].min).to_a
#=> [2,3,4]
neighbors = rows.product(cols) - [[row,col]]
#=> [[3,2],3],4],4]]
# ? ? ? ? ? ? ? ?
neighbors.count { |row,col| grid[row][col] }
#=> 3
在每次迭代中,我们需要构建一个将死亡的活细胞 (to_die
) 和将成为活的死细胞 (to_alive
) 的数组。这可以按如下方式完成。
def transitions(grid)
rows = 0..grid.size - 1
cols = 0..grid.first.size - 1
rows.each_with_object([]) do |i,cells_to_flip|
cols.each do |j|
cell = [i,j]
n = neighbors_alive(grid,cell)
if grid[i][j] # alive
cells_to_flip << cell unless [2,3].include?(cell)
else # dead
cells_to_flip << cell if n == 3
end
end
end
end
cells_to_flip = transitions(grid)
#=> [[2,3]]
然后我们需要更新网格。
def update_grid(grid,cells_to_flip)
cells_to_flip.each { |i,j| grid[i][j] = ! grid[i][j] }
end
让我们尝试使用 grid
的深层副本(因此我们不会修改原始 grid
,它将在下面的 conway(grid)
中使用),使用 {{1} 的值}} 和 to_die
以上。
to_alive
我们看到所有活细胞都死了,arr = grid.dup.map(&:dup)
update_grid(arr,cells_to_flip)
display_grid(arr)
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
和 [3,2]
处的死细胞又复活了。
我们现在可以编写一个方法来玩这个游戏。回想一下,在每次迭代中,如果活细胞少于两个或三个以上,活细胞就会死亡,如果活细胞恰好有三个,则死细胞会恢复生机。
[5,3]
让我们试试吧。
def conway(grid,delay,max_iterations)
rows = 0..grid.size - 1
cols = 0..grid.first.size - 1
iterations = 0
display_grid(grid)
sleep(delay)
loop do
break if iterations == max_iterations
iterations += 1
cells_to_flip = transitions(grid)
break if cells_to_flip.empty?
update_grid(grid,cells_to_flip)
display_grid(grid)
sleep(delay)
end
end
这会显示网格三次,间隔两秒,然后退出,因为在最后一次迭代后没有进一步的更改。
conway(grid,2,1_000_000)
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
????????
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。