Skip to content

Instantly share code, notes, and snippets.

@mattdsteele
Forked from steven-s/game_of_life.rb
Created February 12, 2012 05:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mattdsteele/1806563 to your computer and use it in GitHub Desktop.
Save mattdsteele/1806563 to your computer and use it in GitHub Desktop.
Conway's Game of Life with Ruby and RSpec
require 'rspec'
class World
attr_accessor :cells
def initialize
@cells = []
end
def tick
new_world = World.new
# determine if new life should be created, live on, or die
cells.each do |cell|
neighbor_coords(cell).each do |n|
if !cell_at(n[0],n[1]) && !new_world.cell_at(n[0],n[1]) && create_live_cell?(n[0],n[1])
new_world.cells << Cell.new(n[0],n[1])
end
end
neighbor_count = cell_neighbors(cell.x, cell.y).count
unless neighbor_count < 2 || neighbor_count > 3
new_world.cells << Cell.new(cell.x, cell.y)
end
end
new_world
end
def neighbor_coords(cell)
x,y = cell.x, cell.y
[[x,y+1], [x,y-1], [x+1,y], [x+1,y-1], [x+1,y+1], [x-1,y], [x-1,y+1], [x-1,y-1]]
end
def cell_at(x, y)
cells.find { |cell| cell.x == x && cell.y == y }
end
def cell_neighbors(x, y)
cells.find_all do |cell|
unless cell.x == x && cell.y == y
(cell.x - x).abs <= 1 && (cell.y - y).abs <= 1
end
end
end
def create_live_cell?(x, y)
cell_neighbors(x, y).count == 3
end
end
class Cell
attr_accessor :x, :y
def initialize(x, y)
@x = x
@y = y
end
end
describe 'game_of_life' do
context 'world methods' do
subject { World.new }
it 'create empty new worlds' do
subject.cells.count.should == 0
end
it 'add cells to worlds' do
subject.cells << Cell.new(1, 3)
subject.cells.count.should == 1
end
it 'create new world when determining next state' do
new_world = subject.tick
new_world.should_not == subject
end
it 'locate nothing at coordinates without cells' do
subject.cell_at(1, 3).should be_nil
end
it 'locate cells at coordinates' do
subject.cells << Cell.new(1, 3)
subject.cell_at(1, 3).should_not be_nil
end
it 'determine that a cell has no neighbors' do
subject.cells << Cell.new(0, 0)
subject.cell_neighbors(0, 0).count.should == 0
end
it 'determine that a cell has a neighbor to the east' do
subject.cells << Cell.new(0, 0) << Cell.new(1, 0)
subject.cell_neighbors(0, 0).count.should == 1
end
it 'determine that a cell has a neighbor to the west' do
subject.cells << Cell.new(0, 0) << Cell.new(1, 0)
subject.cell_neighbors(1, 0).count.should == 1
end
it 'determine that a cell has a neighbor to the north' do
subject.cells << Cell.new(0, 0) << Cell.new(0, 1)
subject.cell_neighbors(0, 0).count.should == 1
end
it 'determine that a cell has a neighbor to the south' do
subject.cells << Cell.new(0, 0) << Cell.new(0, 1)
subject.cell_neighbors(0, 1).count.should == 1
end
it 'determine that a cell has a neighbor to the northeast' do
subject.cells << Cell.new(0, 0) << Cell.new(1, 1)
subject.cell_neighbors(0, 0).count.should == 1
end
it 'determine that a cell has a neighbor to the southwest' do
subject.cells << Cell.new(0, 0) << Cell.new(1, 1)
subject.cell_neighbors(1, 1).count.should == 1
end
it 'determine that a cell has a neighbor to the northwest' do
subject.cells << Cell.new(0, 0) << Cell.new(-1, 1)
subject.cell_neighbors(0, 0).count.should == 1
end
it 'determine that a cell has a neighbor to the southeast' do
subject.cells << Cell.new(0, 0) << Cell.new(-1, 1)
subject.cell_neighbors(-1, 1).count.should == 1
end
it 'determine that a cell should not come to life' do
subject.cells << Cell.new(-1, 0) << Cell.new(1, 0)
subject.create_live_cell?(0, 0).should be_false
end
it 'determine that a cell should come to life' do
subject.cells << Cell.new(0, 0) << Cell.new(1, 0) << Cell.new(0, 1)
subject.create_live_cell?(1, 1).should be_true
end
end
context 'cell methods' do
subject { Cell.new(1, 3) }
it 'give coordinates' do
subject.x.should == 1
subject.y.should == 3
end
end
let(:world) { World.new }
it 'follows Rule 1.1: Any live cell with no live neighbors dies, as if caused by under-population' do
world.cells << Cell.new(0, 0)
new_world = world.tick
new_world.cell_at(0, 0).should be_nil
end
it 'follows Rule 1.2: Any live cell with only one live neighbor dies, as if caused by under-population' do
world.cells << Cell.new(0, 0) << Cell.new(1, 0)
new_world = world.tick
new_world.cell_at(0, 0).should be_nil
new_world.cell_at(1, 0).should be_nil
end
it 'follows Rule 2.1: Any live cell with two live neighbors lives on to the next generation' do
world.cells << Cell.new(0, 0) << Cell.new(-1, 0) << Cell.new(1, 0)
new_world = world.tick
new_world.cell_at(0, 0).should_not be_nil
end
it 'follows Rule 2.2: Any live cell with three live neighbors lives on to the next generation' do
world.cells << Cell.new(0, 0) << Cell.new(-1, 0) << Cell.new(1, 0) << Cell.new(0, 1)
new_world = world.tick
new_world.cell_at(0, 0).should_not be_nil
end
it 'follows Rule 3: Any live cell with more than three live neighbors dies, as if by overcrowding' do
world.cells << Cell.new(0, 0) << Cell.new(-1, 0) << Cell.new(1, 0) << Cell.new(0, 1) << Cell.new(0, -1)
new_world = world.tick
new_world.cell_at(0, 0).should be_nil
end
it 'follows Rule 4.1: Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction (north/south)' do
world.cells << Cell.new(0, 0) << Cell.new(-1, 0) << Cell.new(1, 0)
new_world = world.tick
new_world.cell_at(0, 1).should_not be_nil
new_world.cell_at(0, -1).should_not be_nil
end
it 'follows Rule 4.2: Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction (east/west)' do
world.cells << Cell.new(0, 0) << Cell.new(0, 1) << Cell.new(0, -1)
new_world = world.tick
new_world.cell_at(-1, 0).should_not be_nil
new_world.cell_at(1, 0).should_not be_nil
end
it 'follows Rule 4.3: Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction (northeast)' do
world.cells << Cell.new(-1, 1) << Cell.new(1, 1) << Cell.new(-1, -1)
new_world = world.tick
new_world.cell_at(0, 0).should_not be_nil
end
it 'follows Rule 4.4: Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction (northwest)' do
world.cells << Cell.new(-1, 1) << Cell.new(1, 1) << Cell.new(1, -1)
new_world = world.tick
new_world.cell_at(0, 0).should_not be_nil
end
it 'follows Rule 4.5: Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction (southeast)' do
world.cells << Cell.new(-1, -1) << Cell.new(1, -1) << Cell.new(-1, 1)
new_world = world.tick
new_world.cell_at(0, 0).should_not be_nil
end
it 'follows Rule 4.6: Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction (southwest)' do
world.cells << Cell.new(-1, -1) << Cell.new(1, -1) << Cell.new(1, 1)
new_world = world.tick
new_world.cell_at(0, 0).should_not be_nil
end
it 'creates still life: behive' do
world.cells << Cell.new(0, 0) << Cell.new(1, 1) << Cell.new(2, 1) << Cell.new(3, 0) << Cell.new(2, -1) << Cell.new(1, -1)
new_world = world.tick
new_world.cells.count.should == 6
new_world.cell_at(0, 0).should_not be_nil
new_world.cell_at(1 ,1).should_not be_nil
new_world.cell_at(2, 1).should_not be_nil
new_world.cell_at(3, 0).should_not be_nil
new_world.cell_at(2, -1).should_not be_nil
new_world.cell_at(1, -1).should_not be_nil
end
it 'creates still life: block' do
world.cells << Cell.new(0, 0) << Cell.new(1, 0) << Cell.new(0, 1) << Cell.new(1, 1)
new_world = world.tick
new_world.cells.count.should == 4
new_world.cell_at(0, 0).should_not be_nil
new_world.cell_at(1, 0).should_not be_nil
new_world.cell_at(0, 1).should_not be_nil
new_world.cell_at(1, 1).should_not be_nil
end
it 'creates oscillator: blinker' do
world.cells << Cell.new(0, 0) << Cell.new(1, 0) << Cell.new(-1, 0)
new_world = world.tick
new_world.cells.count.should == 3
new_world.cell_at(0, 0).should_not be_nil
new_world.cell_at(0, 1).should_not be_nil
new_world.cell_at(0, -1).should_not be_nil
next_iteration = new_world.tick
next_iteration.cells.count.should == 3
next_iteration.cell_at(0, 0).should_not be_nil
next_iteration.cell_at(1, 0).should_not be_nil
next_iteration.cell_at(-1, 0).should_not be_nil
end
it 'creates oscillator: beacon' do
world.cells << Cell.new(0, 2) << Cell.new(0, 3) << Cell.new(1, 3)
world.cells << Cell.new(2, 0) << Cell.new(3, 0) << Cell.new(3, 1)
new_world = world.tick
new_world.cells.count.should == 8
new_world.cell_at(0, 2).should_not be_nil
new_world.cell_at(0, 3).should_not be_nil
new_world.cell_at(1, 3).should_not be_nil
new_world.cell_at(2, 0).should_not be_nil
new_world.cell_at(3, 0).should_not be_nil
new_world.cell_at(3, 1).should_not be_nil
new_world.cell_at(1, 2).should_not be_nil
new_world.cell_at(2, 1).should_not be_nil
next_iteration = new_world.tick
next_iteration.cells.count.should == 6
next_iteration.cell_at(0, 2).should_not be_nil
next_iteration.cell_at(0, 3).should_not be_nil
next_iteration.cell_at(1, 3).should_not be_nil
next_iteration.cell_at(2, 0).should_not be_nil
next_iteration.cell_at(3, 0).should_not be_nil
next_iteration.cell_at(3, 1).should_not be_nil
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment