Нено обнови решението на 19.12.2011 04:47 (преди около 13 години)
+module GameOfLife
+
+ class Board
+ include Enumerable
+
+ def initialize(*cells)
+ # cells is [[]] after Board.new [], we don't want the empty member
+ cells = cells.reject { |e| e == [] }
+ @cells = cells.uniq.map { |cell| Cell.new cell[0], cell[1] }
+ end
+
+ def next_generation
+ died_cells = @cells.select { |cell| not (2..3).include? living_neighbours(cell).size }
+ born_cells = all_dead_neighbours.select { |n| living_neighbours(n).size == 3 }
+ Board.new *(@cells - died_cells + born_cells).map(&:to_a)
+ end
+
+ def [](x, y)
+ @cells.member? Cell.new x, y
+ end
+
+ def count
+ @cells.size
+ end
+
+ def each(&block)
+ @cells.map { |c| [c.x, c.y] }.each &block
+ end
+
+ private
+
+ def living_neighbours(cell)
+ cell.neighbours.select { |cell| self[cell.x, cell.y] }
+ end
+
+ def dead_neighbours(cell)
+ cell.neighbours - living_neighbours(cell)
+ end
+
+ def all_dead_neighbours
+ @cells.reduce([]) { |acc, cell| acc + dead_neighbours(cell) }.uniq
+ end
+
+ class Cell
+ attr_reader :x, :y
+
+ def initialize(x, y)
+ @x, @y = x, y
+ end
+
+ def neighbours
+ offsets = [-1, 0, 1].repeated_permutation(2).reject { |offset| offset == [0, 0] }
+ offsets.map { |offset| Cell.new(@x + offset[0], @y + offset[1]) }
+ end
+
+ def to_a
+ [@x, @y]
+ end
+
+ def to_s
+ "[#{@x}, #{@y}]"
+ end
+
+ def ==(other)
+ @x == other.x and @y == other.y
+ end
+
+ alias eql? ==
+
+ def hash
+ 37*(37*17 + @x) + @y
+ end
+ end
+ end
+
+end
Cell#hash
, nice :)
Иначе, съвсем леко си го over-engineer-нал :) Трябва да си поговорим в някое междучасие за някои конструкции.