这是我尝试用Ruby编写康威的生命游戏(http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life#Rules)。
我对“count_neighbours”方法有一个非常具体的问题。基本上当我到达网格的边缘时,我会得到一些奇怪的行为。当我解析第0行并到达最后一列(Cloumn 4)时,它会执行以下操作:
评估细胞:R:0 C:4
一个好处是“R:-1”基本上将评估包装到网格的底部,就好像网格的边缘是真正连接的一样。我喜欢无边网格的想法。
这里的坏处是该方法试图评估不存在的“C:5”(第5列),因为在此示例中网格是列0-4。所以这是我寻求帮助解决的第一个问题。理想情况下,我想评估第0列。
当方法尝试评估网格上的最后一行时,下一个问题是,第4行。当方法尝试评估“R:5”时,会抛出一个错误。错误是“未定义的方法`[]'为nil:NilClass(NoMethodError)”因为该行不存在。为了避免抛出错误,我在注释“#This line is a hack”下添加了一行,但我希望能够在没有错误的情况下评估此行。
我最后一个问题是,为什么超出最后一行到第5行抛出并且超出最后一列时出错并不会抛出错误?
#Dimensions for the game grid
WIDTH = 5
HEIGHT = 5
def rand_cell
rand(2)
end
def starting_grid
#Initialise the playing grid
@start_grid = Array.new(WIDTH){Array.new(HEIGHT)}
#Randomly generate starting state for each cell on the grid
@start_grid.each_with_index do |row, rindex|
row.each_with_index do |col, cindex|
@start_grid[rindex][cindex] = rand_cell
end
end
end
def next_grid
#build the next generation's grid to load values into
@next_gen_grid = Array.new(WIDTH){Array.new(HEIGHT)}
#parse each cell in the start grid to see if it lives in the next round
@start_grid.each_with_index do |row, rindex|
row.each_with_index do |col, cindex|
puts "\n\nEvaluating cell: R: #{rindex} C: #{cindex}"
@next_gen_grid[rindex][cindex] = will_cell_survive(rindex, cindex)
end
end
#move the newly generated grid to the start grid as a sterting point for the next round
@start_grid = @next_gen_grid
end
def show_grid(grid)
#Display the evolving cell structures in the console
grid.each_with_index do |row, rindex|
row.each_with_index do |col, cindex|
if grid[rindex][cindex] == 1
print "️⬛️ "
else
print "⬜️ ️"
end
end
puts "\n"
end
end
def count_neighbours(row, col)
cell_count = 0
rows = [-1, 0, 1]
cols = [-1, 0, 1]
rows.each do |r|
cols.each do |c|
#ingnore the cell being evaluated
unless c == 0 && r == 0
#This line is a hack to stop an error when evaluating beyond the last row
if row != HEIGHT-1
puts "Evaluating neighbor R: #{row+r} C: #{col+c}. State: #{@start_grid[(row+r)][(col+c)]}"
if @start_grid[(row+r)][(col+c)] == 1
cell_count += 1
end
end
end
end
end
puts "Neighbour count is #{cell_count}"
return cell_count
end
def will_cell_survive(rindex, cindex)
count = count_neighbours(rindex, cindex)
#If the cell being evaluated is currently alive
if @start_grid[rindex][cindex] == 1
#test rule 1
if alive_rule1(count)
puts "Rule 1"
return 0
#test rule 2
elsif alive_rule2(count)
puts "Rule 2"
return 1
elsif
#test rule 3
puts "Rule 3"
return 0
end
#If the cell being evaluated is currently dead
else
#test rule 4
alive_rule4(count)
puts "Rule 4"
return 1
end
end
def alive_rule1(neighbour_count)
neighbour_count < 2
end
def alive_rule2(neighbour_count)
neighbour_count == 2 || neighbour_count == 3
end
def alive_rule3(neighbour_count)
neighbour_count > 3
end
def alive_rule4(neighbour_count)
neighbour_count == 3
end
#Run just one round of the game
system "clear"
starting_grid
show_grid(@start_grid)
puts "\n\n"
next_grid
show_grid(@next_gen_grid)
#Initiate the game grid
# system "clear"
# starting_grid
#Run the game
# 200.times do |t|
# system "clear"
# puts "\n\n"
# next_grid
# puts "Grid #{t}"
# show_grid(@next_gen_grid)
# sleep(0.25)
# end
[编辑]:实施答案的代码位于https://github.com/AxleMaxGit/ruby-conways-game
答案 0 :(得分:3)
如果你想将边缘彼此连接起来(顺便说一下,它会形成一个&#34;圆环&#34;形状,或者你喜欢的是&#34;小行星&#34;世界模型你永远不能离开屏幕)然后最简单的调整是模块化算术:
更改:
if @start_grid[(row+r)][(col+c)] == 1
要:
if @start_grid[(row+r) % HEIGHT][(col+c) % WIDTH] == 1
运算符符号%
是模运算,并根据需要精确地执行环绕逻辑。
超越最后一行的原因与超越最后一列的行为不同的原因是:
@start_grid[ 3 ][ 5 ] == nil
在您检查邻居时返回false,其他所有内容都正常工作。
然而,
@start_grid[ 5 ][ 3 ]
是一个问题,因为@start_grid[ 5 ]
是nil
,所以它实际上是
nil[ 3 ]
抛出错误是因为Ruby没有解析[]
对nil
的含义的逻辑。