Question

Voici ma tentative d'écrire Game of Life de Conway (http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life#Rules) en Ruby.

J'ai une question très précise sur la méthode "count_neighbours".Fondamentalement, lorsque j'arrive au bord de la grille, j'obtiens un comportement étrange.Lorsque j'analyse la ligne 0 et que j'atteins la dernière colonne (Cloumn 4), cela ressemble à ceci :

Cellule d'évaluation :R :0C :4

  • Évaluation du voisin R :-1°C :3.État:0
  • Évaluation du voisin R :-1°C :4.État:1
  • Évaluation du voisin R :-1°C :5.État:
  • Évaluation du voisin R :0C :3.État:0
  • Évaluation du voisin R :0C :5.État:
  • Évaluation du voisin R :1C :3.État:1
  • Évaluation du voisin R :1C :4.État:0
  • Évaluation du voisin R :1C :5.État:

Une bonne chose est que "R :-1" enveloppe essentiellement l'évaluation jusqu'au bas de la grille comme si les bords de la grille étaient réellement connectés.J'aime l'idée d'une grille sans bord.

Le problème ici est que la méthode essaie d'évaluer "C :5" (Colonne 5) qui n'existe pas car dans cet exemple la grille est constituée des colonnes 0 à 4.Donc c'est le premier problème que je cherche à résoudre.Idéalement, je veux ici évaluer la colonne 0.

Le le prochain problème est lorsque la méthode tente d'évaluer la dernière ligne de la grille, la ligne 4.Lorsque la méthode tente d'évaluer "R :5", une erreur est générée.L'erreur est « méthode non définie `[ ]' pour nil:NilClass (NoMethodError) » car cette ligne n'existe pas.Pour éviter que l'erreur ne soit générée, j'ai ajouté la ligne sous le commentaire "#Cette ligne est un hack" mais je veux pouvoir évaluer cette ligne sans erreur.

Le dernière question que j'ai est-ce pourquoi aller au-delà de la dernière ligne jusqu'à la ligne 5 génère une erreur alors que dépasser la dernière colonne ne génère pas d'erreur ?

    #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

[MODIFIER]:Le code avec la réponse implémentée se trouve à https://github.com/AxleMaxGit/ruby-conways-game

Était-ce utile?

La solution

Si vous souhaitez relier les bords les uns aux autres (ce qui crée d'ailleurs une forme de "tore", ou si vous préférez le modèle mondial "astéroïdes" où vous ne pouvez jamais quitter l'écran), alors le réglage le plus simple est de travailler en mode modulaire. arithmétique:

Changement:

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

À:

if @start_grid[(row+r) % HEIGHT][(col+c) % WIDTH] == 1

Le symbole de l'opérateur % est une arithmétique modulaire et exécute la logique de bouclage précisément selon vos besoins.

La raison pour laquelle le dépassement de la dernière ligne se comporte différemment du dépassement de la dernière colonne est la suivante :

@start_grid[ 3 ][ 5 ] == nil

qui renvoie false dans votre chèque pour le voisin, et tout le reste fonctionne normalement.

Cependant,

@start_grid[ 5 ][ 3 ]

est un problème, parce que @start_grid[ 5 ] est nil, c'est donc effectivement

nil[ 3 ]

l'erreur est générée car Ruby n'a aucune logique pour résoudre ce qui [] signifie sur un nil.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top