2014-01-26 2 views
1

명백한 논리 오류에 대한 피드백을 찾고 최적화하지 않았습니다. 마지막 게임 메시지 (예 : 1 tick이 11 tick으로 바뀜)에서 이상한 틱 수가 계속 나타납니다.매우 구체적인 Conway의 Game of Life (Ruby beginner)

코드를 실행하는 동안 발견 할 수있는 가장 큰 오류는 2 차 틱에서 발생하며 매우 많은 양의 살아있는 셀이 나타납니다. 이유를 이해하는 데 너무 익숙하지 않지만 @alive_cells가 각 검사 후에 0으로 다시 설정되지 않는 것처럼 보입니다.

내 코드는 크기가 크지 만 경험이있는 사람에게는 어린이의 놀이가되어야합니다.

class CellGame 

def initialize 

    puts "How big do you want this game?" 
    @size = gets.chomp.to_i 

    @cell_grid = Array.new(@size) { Array.new(@size) } 
    @grid_storage = Array.new(@size) { Array.new(@size) } 

    @tick_count = 0 

    fill_grid_with_random_cells 
end 

def fill_grid_with_random_cells 
    @cell_grid.each do |row| 
    row.map! do |cell| 
     roll = rand(10) 
     if roll > 9 
      "•" 
     else 
      " " 
     end 
    end 
    end 

    check_cells_for_future_state 
end 

def check_for_any_alive_cells 

    @cell_grid.each do |row| 
    if row.include?("•") 
     check_cells_for_future_state 
    break 
    else 
     end_game_print_result 
    end 
    end 
end 


def check_cells_for_future_state 

    @cell_grid.each_with_index do |row, row_index| 
    row.each_with_index do |cell, cell_index| 
     @live_neighbors = 0 

     add_row_shift = (row_index + 1) 
     if add_row_shift == @size 
     add_row_shift = 0 
     end 

     add_cell_shift = (cell_index + 1) 
     if add_cell_shift == @size 
     add_cell_shift = 0 
     end 

     def does_this_include_alive(cell) 
     if cell.include?("•") 
      @live_neighbors +=1 
     end 
     end 

     top_left_cell = @cell_grid[(row_index - 1)][(cell_index - 1)] 
     does_this_include_alive(top_left_cell) 

     top_cell = @cell_grid[(row_index - 1)][(cell_index)] 
     does_this_include_alive(top_cell) 

     top_right_cell = @cell_grid[(row_index - 1)][(add_cell_shift)] 
     does_this_include_alive(top_right_cell) 

     right_cell = @cell_grid[(row_index)][(add_cell_shift)] 
     does_this_include_alive(right_cell) 

     bottom_right_cell = @cell_grid[(add_row_shift)][(add_cell_shift)] 
     does_this_include_alive(bottom_right_cell) 

     bottom_cell = @cell_grid[(add_row_shift)][(cell_index)] 
     does_this_include_alive(bottom_cell) 

     bottom_left_cell = @cell_grid[(add_row_shift)][(cell_index - 1)] 
     does_this_include_alive(bottom_left_cell) 

     left_cell = @cell_grid[(row_index)][(cell_index - 1)] 
     does_this_include_alive(left_cell) 


     if @live_neighbors == 2 || @live_neighbors == 3 
     @grid_storage[row_index][cell_index] = "•" 
     else 
     @grid_storage[row_index][cell_index] = " " 
     end 

    end 
    end 

    update_cell_grid 
end 

def update_cell_grid 
    @cell_grid = @grid_storage 

    print_cell_grid_and_counter 
end 


def print_cell_grid_and_counter 

    system"clear" 
    @cell_grid.each do |row| 
    row.each do |cell| 
     print cell + " " 
    end 
    print "\n" 
    end 

    @tick_count += 1 
    print "\n" 
    print "Days passed: #{@tick_count}" 
    sleep(0.25) 
    check_for_any_alive_cells 
end 


def end_game_print_result 
    print "#{@tick_count} ticks were played, end of game." 
    exit 
end 


end 

답변

2

코드가 잘못 된 부분을 볼 수 없습니다. 이상한 행동을 쉽게 일으킬 수있는 재귀 호출이 있습니다. 여기에 내가 무엇을 최대 온 것입니다 :

class CellGame 
    def initialize(size) 
    @size = size; @archive = [] 
    @grid = Array.new(size) { Array.new(size) { rand(3).zero? } } 
    end 

    def lives_on?(row, col) 
    neighborhood = (-1..1).map { |r| (-1..1).map { |c| @grid[row + r] && @grid[row + r][col + c] } } 
    its_alive = neighborhood[1].delete_at(1) 
    neighbors = neighborhood.flatten.count(true) 
    neighbors == 3 || neighbors == 2 && its_alive 
    end 

    def next_gen 
    ([email protected]).map { |row| ([email protected]).map { |col| lives_on?(row, col) } } 
    end 

    def play 
    tick = 0; incr = 1 
    loop do 
     @archive.include?(@grid) ? incr = 0 : @archive << @grid 
     sleep(0.5); system "clear"; @grid = next_gen 
     puts "tick - #{tick += incr}" 
     puts @grid.map { |row| row.map { |cell| cell ? '*' : ' ' }.inspect } 
    end 
    end 
end 

cg = CellGame.new 10 
cg.play 

틱 카운트 중지하지만 프로그램 마지막에 오실레이터를 통해 실행 유지합니다.

+0

+1 'lives_on?'방법은 아름다움의 것입니다. –

+0

@ Mark_Thomas - 고마워요. 이것에 대한 지출 시간이 너무 길어집니다. – seph

+0

이 남자를 들여다 주셔서 감사합니다. 나는 이것을 공부해야합니다. 그래서 당신이 지금 하하 한 것을 이해하십시오. – Stringy

0

나는 이것을 재검토하고 싶었고 자신있게 말했음을 알았습니다! 여기 내 새로운 솔루션 - 여전히 초보자를 중점적으로 다룹니다. 누군가가 도움이되기를 바랍니다.

class Game 

    # Uses constants for values that won't change 
    LIVE = "" 
    DEAD = " " 
    WIDTH = 68 
    HEIGHT = 34 

    def initialize 
    # Sets our grid to a new empty grid (set by method below) 
    @grid = empty_grid 

    # Randomly fills our grid with live cells 
    @grid.each do |row| 
     # Map will construct our new array, we use map! to edit the @grid 
     row.map! do |cell| 
     if rand(10) == 1 
      LIVE # Place a live cell 
     else 
      DEAD # Place a dead cell 
     end 
     end 
    end 

    # Single line implimentation 
    # @grid.each {|row|row.map! {|cell|rand(10) == 1 ? LIVE : DEAD}} 

    loop_cells #start the cycle 
    end 

    def empty_grid 
    Array.new(HEIGHT) do 
     # Creates an array with HEIGHT number of empty arrays 
     Array.new(WIDTH) do 
     # Fills each array with a dead cell WIDTH number of times 
     DEAD 
     end 
    end 

    # Single line implimentation 
    # Array.new(HEIGHT){ Array.new(WIDTH) { DEAD } } 
    end 

    def print_grid # Prints our grid to the terminal 
    system "clear" # Clears the terminal window 

    # Joins cells in each row with an empty space 
    rows = @grid.map do |row| 
     row.join(" ") 
    end 

    # Print rows joined by a new line 
    print rows.join("\n") 

    # Single line implimentation 
    # print @grid.map{|row| row.join(" ")}.join("\n") 
    end 

    def loop_cells 
    print_grid # Start by printing the current grid 
    new_grid = empty_grid # Set an empty grid (this will be the next life cycle) 

    # Loop through every cell in every row 
    @grid.each_with_index do |row, row_index| 
     row.each_with_index do |cell, cell_index| 

     # Find the cells friends 
     friends = find_friends(row_index, cell_index) 

     # Apply life or death rules 
     if cell == LIVE 
      state = friends.size.between?(2,3) 
     else 
      state = friends.size == 3 
     end 

     # Set cell in new_grid for the next cycle 
     new_grid[row_index][cell_index] = state ? LIVE : DEAD 

     end 
    end 

    # Replace grid and start over 
    @grid = new_grid 
    start_over 
    end 

    def find_friends(row_index, cell_index) 

    # Ruby can reach backwards through arrays and start over at the end - but it cannot reach forwards. If we're going off the grid, start over at 0 
    row_fix = true if (row_index + 1) == HEIGHT 
    cell_fix = true if (cell_index + 1) == WIDTH 
    # You'll see below I will use 0 if one of these values is truthy when checking cells to the upper right, right, lower right, lower, and lower left. 

    # Check each neighbor, use 0 if we're reaching too far 
    friends = [ 
     @grid[(row_index - 1)][(cell_index - 1)], 
     @grid[(row_index - 1)][(cell_index)], 
     @grid[(row_index - 1)][(cell_fix ? 0 : cell_index + 1)], 
     @grid[(row_index)][(cell_fix ? 0 : cell_index + 1)], 
     @grid[(row_fix ? 0 : row_index + 1)][(cell_fix ? 0 : cell_index + 1)], 
     @grid[(row_fix ? 0 : row_index + 1)][(cell_index)], 
     @grid[(row_fix ? 0 : row_index + 1)][(cell_index - 1)], 
     @grid[(row_index)][(cell_index - 1)] 
    ] 

    # Maps live neighbors into an array, removes nil values 
    friends.map{|x| x if x == LIVE}.compact 
    end 

    def start_over 
    sleep 0.1 
    loop_cells 
    end 

end 

# Start game when file is run 
Game.new 
관련 문제