public
Last active

Kanye's Game of Life

  • Download Gist
conway_spec.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
class Point < Struct.new(:x,:y)
def self.at(x,y)
new x, y
end
 
def ==(other)
other.x == x and other.y == y
end
 
def around
-1.upto(1).map do |diff_x|
-1.upto(1).map do |diff_y|
next if diff_x == 0 and diff_y == 0
self.class.at(x + diff_x,y + diff_y)
end
end.flatten.compact
end
end
 
class Cell
def self.at(x,y)
AliveCell.new Point.at(x,y)
end
 
def initialize(position)
@position = position
@neighbors = 0
end
 
attr_reader :position, :neighbors
 
def neighbored
@neighbors += 1
end
 
def to_s
"#{self.class.name} @ #{position.x},#{position.y} - Neighbors: #{neighbors}"
end
end
 
class AliveCell < Cell
def transform
AliveCell.new(position) if neighbors == 2 || neighbors == 3
end
end
 
class DeadCell < Cell
def transform
AliveCell.new(position) if neighbors == 3
end
end
 
class Board
 
def initialize(cells=[])
cells.each {|cell| add cell }
end
 
def cells
@cells ||= Hash.new {|hash,position| hash[position] = DeadCell.new(position)}
end
 
def alive_cells
cells.values.find_all {|cell| cell.is_a? AliveCell }
end
 
def add(cell)
cell.position.around.each do |position|
found_cell = cells[position]
found_cell.neighbored
cell.neighbored if found_cell.is_a? AliveCell
end
 
cells[cell.position] = cell
end
 
def tick
surviving_cells = cells.values.map {|cell| cell.transform }.compact
self.class.new surviving_cells
end
end
 
describe Board do
 
describe '#tick' do
context "when the board has one lonely cell" do
#
# X => 0
#
it "generates a board with no alive cells" do
cell1 = Cell.at 0, 0
board = Board.new
board.add cell1
board = board.tick
expect(board.alive_cells).to have(0).cells
end
end
 
context "when the board has two lonely cells" do
#
# XX => 00
#
it "generates a board with no alive cells" do
cell1 = Cell.at 0, 0
cell2 = Cell.at 1, 0
board = Board.new
board.add cell1
board.add cell2
board = board.tick
expect(board.alive_cells).to have(0).cells
end
end
 
context "when the board has three neighboring cells" do
#
# X => XX => XX
# XX => XX => XX
#
it "generates the correct board" do
cell1 = Cell.at 0, 0
cell2 = Cell.at 1, 0
cell3 = Cell.at 1, 1
 
board = Board.new
board.add cell1
board.add cell2
board.add cell3
board = board.tick
expect(board.alive_cells).to have(4).cells
board = board.tick
# Four cells next to each other are in perfect harmony
expect(board.alive_cells).to have(4).cells
end
end
 
 
context "when a board has five live cells" do
#
# X => XXX => XXX => XXX
# XXX => X0X => X0X => X0X
# X => XXX => XXX => XXX
#
it "generates the correct board" do
cell1 = Cell.at 0, 0
cell2 = Cell.at 1, 0
cell3 = Cell.at 0, 1
cell4 = Cell.at -1,0
cell5 = Cell.at 0,-1
 
board = Board.new
board.add cell1
board.add cell2
board.add cell3
board.add cell4
board.add cell5
board = board.tick
expect(board.alive_cells).to have(8).cells
board = board.tick
expect(board.alive_cells).to have(8).cells
end
end
end
 
end

A Conway's Game of Life solution with the attempt at being approachable from a OOP perspective, while maintaining elegance in execution.

cells.values.grep(AliveCell)

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.