Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 解析康威';s游戏网格_Ruby_Arrays_Parsing_Conways Game Of Life - Fatal编程技术网

Ruby 解析康威';s游戏网格

Ruby 解析康威';s游戏网格,ruby,arrays,parsing,conways-game-of-life,Ruby,Arrays,Parsing,Conways Game Of Life,以下是我试图用Ruby编写Conway的生命游戏()的尝试 我有一个非常具体的问题,关于“计算邻居”的方法。基本上,当我到达网格边缘时,我会有一些奇怪的行为。当我解析第0行并到达最后一列(Cloumn 4)时,它会执行如下操作: 计算单元:R:0 C:4 评价邻域R:-1c:3。州:0 评价邻域R:-1c:4。国家:1 评估邻居R:-1 C:5。声明: 评估邻居R:0c:3。州:0 评估邻居R:0c:5。声明: 评价邻域R:1c:3。国家:1 评价邻域R:1c:4。州:0 评价邻域R:1c:5

以下是我试图用Ruby编写Conway的生命游戏()的尝试

我有一个非常具体的问题,关于“计算邻居”的方法。基本上,当我到达网格边缘时,我会有一些奇怪的行为。当我解析第0行并到达最后一列(Cloumn 4)时,它会执行如下操作:

计算单元:R:0 C:4

  • 评价邻域R:-1c:3。州:0
  • 评价邻域R:-1c:4。国家:1
  • 评估邻居R:-1 C:5。声明:
  • 评估邻居R:0c:3。州:0
  • 评估邻居R:0c:5。声明:
  • 评价邻域R:1c:3。国家:1
  • 评价邻域R:1c:4。州:0
  • 评价邻域R:1c:5。声明:
一个好的方面是,“R:-1”实质上将计算环绕到网格底部,就好像网格的边是真正连接的一样。我喜欢无边网格的想法

这里的缺点是,该方法试图计算“C:5”(第5列),但该列不存在,因为在本例中,网格是第0-4列。因此,这是我寻求帮助解决的第一个问题。理想情况下,我希望计算列0

下一个问题是当该方法尝试评估网格上的最后一行,即第4行时。当该方法尝试计算“R:5”时,会抛出一个错误。错误为“nil:NilClass(NoMethodError)的未定义方法“[]”,因为该行不存在。为了避免抛出错误,我在注释“#这一行是一个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
#游戏网格的尺寸
宽度=5
高度=5
def rand_电池
兰特(2)
结束
def起动格栅
#初始化播放网格
@start_grid=Array.new(宽度){Array.new(高度)}
#为网格上的每个单元随机生成起始状态
@开始网格。每个网格都有索引do行,rindex|
行。每个带有索引do的列,cindex|
@启动网格[rindex][cindex]=随机单元
结束
结束
结束
def下一个网格
#构建下一代网格以将值加载到
@next_gen_grid=Array.new(宽度){Array.new(高度)}
#分析起始网格中的每个单元格,查看它是否存在于下一轮中
@开始网格。每个网格都有索引do行,rindex|
行。每个带有索引do的列,cindex|
放置“\n\n计算单元:R:{rindex}C:{cindex}”
@下一代网格[rindex][cindex]=细胞会存活吗(rindex,cindex)
结束
结束
#将新生成的网格移动到起始网格,作为下一轮的存储点
@开始网格=@next\u gen\u网格
结束
def显示网格(网格)
#在控制台中显示不断演变的单元结构
grid.each_与_索引do|行,rindex|
行。每个带有索引do的列,cindex|
如果网格[rindex][cindex]==1
“打印”️⬛️ "
其他的
“打印”⬜️ ️"
结束
结束
放入“\n”
结束
结束
def计数(行、列)
单元格计数=0
行=[-1,0,1]
cols=[-1,0,1]
行。每行做| r|
每种颜色都有| c|
#ingnore正在评估的单元格
除非c==0&&r==0
#这一行是一种在计算超过最后一行时停止错误的方法
如果行!=高度-1
将“计算邻居R:#{row+R}C:#{col+C}。状态:#{@start_网格[(行+r)][(列+c)]}”
如果@start_网格[(行+r)][(列+c)]==1
单元计数+=1
结束
结束
结束
结束
结束
放置“邻居计数为#{cell_count}”
返回单元计数
结束
def细胞将存活(rindex,cindex)
计数=计数(rindex、cindex)
#如果正在计算的单元格当前处于活动状态
如果@start_grid[rindex][cindex]==1
#测试规则1
如果活动(规则1)(计数)
“规则1”
返回0
#测试规则2
elsif活动规则2(计数)
把“规则2”
返回1
埃尔西夫
#测试规则3
“规则3”
返回0
结束
#如果正在评估的单元格当前已死亡
其他的
#测试规则4
现行规则4(计数)
把“规则4”
返回1
结束
结束
def活动规则1(邻居计数)
相邻单元计数<2
结束
def活动规则2(邻居计数)
邻居计数=2 | |邻居计数=3
结束
def活动规则3(邻居计数)
邻接计数>3
结束
def活动规则4(邻居计数)
邻接计数==3
结束
#只跑一轮比赛
系统“清除”
启动网格
显示网格(@start\u网格)
放置“\n\n”
下一个网格
显示网格(@next\u gen\u grid)
#启动游戏网格
#系统“清除”
#启动网格
#运行游戏
#200.5倍|
#系统“清除”
#放置“\n\n”
#下一个网格
#放置“网格#{t}”
#显示网格(@next\u gen\u grid)
#睡眠(0.25)
#结束

[编辑]:实现答案的代码位于

如果您想将边相互连接(顺便说一下,这会创建一个“圆环”形状,或者如果您更喜欢永远无法离开屏幕的“小行星”世界模型),那么最简单的调整就是使用模块化算法:

更改:

if @start_grid[(row+r)][(col+c)] == 1
致:

运算符符号
%
是模块化算术,并根据需要精确执行环绕逻辑

超出最后一行与超出最后一列的行为不同的原因是:

@start_grid[ 3 ][ 5 ] == nil
在您的邻居支票中返回false,其他一切正常

但是,

@start_grid[ 5 ][ 3 ]
是一个问题,因为
@start\u grid[5]
nil
,所以它是有效的

nil[ 3 ]

抛出此错误是因为Ruby没有逻辑来解析
[]
nil
上的含义,谢谢你的回答。非常聪明。:-)
nil[ 3 ]