Петър обнови решението на 19.12.2011 12:35 (преди около 13 години)
+# encoding: UTF-8
+module GameOfLife
+ class Cell
+ attr_reader :x, :y
+ attr_accessor :alive
+
+ def initialize(x, y, alive = true)
+ @x = x
+ @y = y
+ @alive = alive
+ end
+
+ def to_a
+ [x, y]
+ end
+ end
+
+ class Rules
+ def self.applay_rules(neighbors_count, cell)
+ if not cell.alive and neighbors_count == 3
+ cell.alive = true
+ elsif cell.alive and neighbors_count < 2
+ cell.alive = false
+ elsif cell.alive and neighbors_count > 3
+ cell.alive = false
+ end
+ end
+
+ end
+
+ class RangeTable
+ include Enumerable
+
+ def initialize(board)
+ @board = board
+ init_range
+ end
+
+ def each
+ (@min_x..@max_x).each do |x|
+ (@min_y..@max_y).each do |y|
+ yield @board.get_cell(x, y).clone
+ end
+ end
+ end
+
+ def neighbors(cell)
+ neighbors = []
+ cross_neighbors(neighbors, cell.x, cell.y)
+ x_neighbors(neighbors, cell.x, cell.y)
+ neighbors
+ end
+
+ private
+
+ def init_range
+ @min_x = @board.collect { |x, y| x}.min - 1
+ @max_x = @board.collect { |x, y| x}.max + 1
+ @min_y = @board.collect { |x, y| y}.min - 1
+ @max_y = @board.collect { |x, y| y}.max + 1
+ end
+
+ def cross_neighbors(neighbors, x, y)
+ neighbors << @board.get_cell(x+1, y) if @board[x+1, y]
+ neighbors << @board.get_cell(x-1, y) if @board[x-1, y]
+ neighbors << @board.get_cell(x, y+1) if @board[x, y+1]
+ neighbors << @board.get_cell(x, y-1) if @board[x, y-1]
+ end
+
+ def x_neighbors(neighbors, x, y)
+ neighbors << @board.get_cell(x+1, y+1) if @board[x+1, y+1]
+ neighbors << @board.get_cell(x-1, y+1) if @board[x-1, y+1]
+ neighbors << @board.get_cell(x+1, y-1) if @board[x+1, y-1]
+ neighbors << @board.get_cell(x-1, y-1) if @board[x-1, y-1]
+ end
+ end
+
+ class NextGeneration
+ def initialize(board)
+ @board = board
+ @range_table = RangeTable.new(@board)
+ end
+
+ def next_generation
+ cells = select_cells
+ Board.new(*cells.map { |cell| cell.to_a })
+ end
+
+ private
+
+ def select_cells
+ @range_table.select do |cell|
+ Rules.applay_rules(@range_table.neighbors(cell).size, cell)
+ cell.alive == true
+ end
+ end
+
+ end
+
+ class Board
+ include Enumerable
+
+ attr_reader :cells
+
+ def initialize(*cells)
+ @cells = []
+ cells.each { |cell| @cells << Cell.new(cell[0], cell[1]) if not self[cell[0], cell[1]]}
+ end
+
+ def each
+ @cells.each { |cell| yield cell.x, cell.y}
+ end
+
+ def [](x, y)
+ get_cell(x, y).alive
+ end
+
+ def count
+ cells.size
+ end
+
+ def next_generation
+ return Board.new if count == 0
+ next_gen = NextGeneration.new(self)
+ next_gen.next_generation
+ end
+
+ def get_cell(x, y)
+ @cells.select { |cell| cell.x == x and cell.y == y }.fetch(0, Cell.new(x, y, false))
+ end
+
+ end
+end