Skip to content

Instantly share code, notes, and snippets.

@marksim
Created November 4, 2011 17:54
Show Gist options
  • Save marksim/1340006 to your computer and use it in GitHub Desktop.
Save marksim/1340006 to your computer and use it in GitHub Desktop.
Game of Life with Rspec
require 'rspec'
class Cell
attr_accessor :x, :y, :world
def initialize(world, x=0, y=0)
@world = world
@x = x; @y = y
@world.add(self)
end
def neighbors
@world.neighbors_of(@x, @y)
end
def die
@world.cells.delete(self)
end
end
class World
attr_accessor :cells
def initialize
@cells = []
end
def self.load(coord_array)
coord_array.each do |x, y|
Cell.new(self, x, y)
end
end
def neighbors_of(x, y)
@cells.select {|c| c.x == x-1 || c.x == x+1 || c.x == x}.
select {|c| c.y == y-1 || c.y == y+1 || c.y == y }.
reject {|c| c.x == x && c.y == y}
end
def dead_near(x, y)
dead = []
(x-1..x+1).each do |x_coord|
(y-1..y+1).each do |y_coord|
dead << [x_coord, y_coord] if cell_at(x_coord, y_coord).nil?
end
end
dead
end
def add(cell)
@cells << cell if cell_at(cell.x, cell.y).nil?
end
def cell_at(x, y)
@cells.select {|c| c.x == x && c.y == y}.first
end
def tick
dying = []
birthing = []
@cells.each do |cell|
dying << cell if cell.neighbors.count < 2
dying << cell if cell.neighbors.count > 3
dead_near(cell.x, cell.y).each do |dx, dy|
birthing << [dx, dy] if neighbors_of(dx, dy).count == 3
end
end
dying.each(&:die)
birthing.each do |x, y|
Cell.new(self, x, y)
end
end
end
describe Cell do
let(:world) { World.new }
context "generally" do
subject { Cell.new(world) }
it "creates a cell " do
subject.should be_a Cell
end
it "creates a cell at given coordinates" do
c = Cell.new(world, 1, 3)
c.x.should == 1
c.y.should == 3
end
it "registers itself with a world" do
c = Cell.new(world, 5, 4)
world.cells.should include c
end
it "knows it has no neighbors" do
subject.neighbors.count.should == 0
end
it "knows it has one neighbor north of it" do
cell = Cell.new(world, 0, 1)
subject.neighbors.count.should == 1
end
it "knows it has one neighbor east of it" do
cell = Cell.new(world, 1, 0)
subject.neighbors.count.should == 1
end
it "knows it has one neighbor south of it" do
cell = Cell.new(world, 0, -1)
subject.neighbors.count.should == 1
end
it "knows it has one neighbor west of it" do
cell = Cell.new(world, -1, 0)
subject.neighbors.count.should == 1
end
it "knows it has one neighbor northeast of it" do
cell = Cell.new(world, 1, 1)
subject.neighbors.count.should == 1
end
it "knows it has one neighbor northwest of it" do
cell = Cell.new(world, -1, 1)
subject.neighbors.count.should == 1
end
it "knows it has one neighbor southeast of it" do
cell = Cell.new(world, 1, -1)
subject.neighbors.count.should == 1
end
it "knows it has one neighbor southwest of it" do
cell = Cell.new(world, -1, -1)
subject.neighbors.count.should == 1
end
end
context "dies off when ticked if fewer than 2 neighbors" do
let(:world) { World.new }
it "dies off when it has 0 neighbors" do
c = Cell.new(world, 1, 1)
world.cells.should include c
world.tick
world.cells.should_not include c
end
it "dies off when it has 1 neighbors" do
Cell.new(world, 1, 2)
c = Cell.new(world, 1, 1)
world.cells.should include c
world.tick
world.cells.should_not include c
end
end
context "lives on when ticked if 2 or 3 neighbors" do
it "lives when it has 2 neighbors" do
Cell.new(world, 1, 2)
Cell.new(world, 2, 1)
c = Cell.new(world, 1, 1)
world.cells.should include c
world.tick
world.cells.should include c
end
it "lives when it has 3 neighbors" do
Cell.new(world, 1, 2)
Cell.new(world, 2, 1)
Cell.new(world, -1, 2)
c = Cell.new(world, 1, 1)
world.cells.should include c
world.tick
world.cells.should include c
end
end
context "dies off when ticked if more than 3 neighbors" do
it "dies when it has 4 neighbors" do
Cell.new(world, -1, -1)
Cell.new(world, -1, 0)
Cell.new(world, -1, 1)
Cell.new(world, 0, -1)
c = Cell.new(world, 0, 0)
world.cells.should include c
world.tick
world.cells.should_not include c
end
it "dies when it has 5 neighbors" do
Cell.new(world, -1, -1)
Cell.new(world, -1, 0)
Cell.new(world, -1, 1)
Cell.new(world, 0, -1)
Cell.new(world, 0, 1)
c = Cell.new(world, 0, 0)
world.cells.should include c
world.tick
world.cells.should_not include c
end
it "dies when it has 6 neighbors" do
Cell.new(world, -1, 1)
Cell.new(world, -1, 0)
Cell.new(world, -1, 1)
Cell.new(world, 0, -1)
Cell.new(world, 0, 1)
Cell.new(world, 1, -1)
c = Cell.new(world, 0, 0)
world.cells.should include c
world.tick
world.cells.should_not include c
end
it "dies when it has 7 neighbors" do
Cell.new(world, -1, 1)
Cell.new(world, -1, 0)
Cell.new(world, -1, 1)
Cell.new(world, 0, -1)
Cell.new(world, 0, 1)
Cell.new(world, 1, -1)
Cell.new(world, 1, 0)
c = Cell.new(world, 0, 0)
world.cells.should include c
world.tick
world.cells.should_not include c
end
it "dies when it has 8 neighbors" do
Cell.new(world, -1, 1)
Cell.new(world, -1, 0)
Cell.new(world, -1, 1)
Cell.new(world, 0, -1)
Cell.new(world, 0, 1)
Cell.new(world, 1, -1)
Cell.new(world, 1, 0)
Cell.new(world, 1, 1)
c = Cell.new(world, 0, 0)
world.cells.should include c
world.tick
world.cells.should_not include c
end
end
context "reproduces if exactly 3 neighbors" do
it "does not reproduce with 2 neighbors" do
Cell.new(world, 1, -1)
Cell.new(world, 1, 0)
world.tick
world.cell_at(0, 0).should be_nil
end
it "does reproduce with 3 neighbors" do
Cell.new(world, 1, -1)
Cell.new(world, 1, 0)
Cell.new(world, 0, 1)
world.tick
world.cell_at(0, 0).should_not be_nil
end
it "does not reproduce with 4 neighbors" do
Cell.new(world, 0, 1)
Cell.new(world, 0, -1)
Cell.new(world, -1, 0)
Cell.new(world, 1, 0)
world.tick
world.cell_at(0, 0).should be_nil
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment