-
-
Save mattdsteele/1806563 to your computer and use it in GitHub Desktop.
Conway's Game of Life with Ruby and RSpec
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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