Created
October 9, 2012 20:22
-
-
Save tylerdooling/3861192 to your computer and use it in GitHub Desktop.
Game of Life
This file contains hidden or 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
# The Game of Life | |
# | |
# Rules | |
# Any live cell with fewer than two live neighbors dies, as if caused by under-population. | |
# Any live cell with two or three live neighbors lives on to the next generation. | |
# Any live cell with more than three live neighbors dies, as if by overcrowding. | |
# Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction. | |
# Example usage | |
# Game.new(150,50).randomize.run 1000 | |
require 'rspec' | |
class Point < Struct.new :x, :y | |
def neighbors | |
@neighbors ||= (((-1..1).to_a * 2).combination(2).to_a.uniq - [[0,0]]).map { |n| | |
Point.new *([[x,y], n].transpose.map { |e| e.reduce :+ }) | |
} | |
end | |
end | |
class Node | |
attr_reader :coordinate, :container | |
attr_accessor :state | |
def initialize(x, y, container) | |
@coordinate = Point.new x, y | |
@container = container | |
@state = :off | |
end | |
def neighbors | |
@neighbors ||= @coordinate.neighbors.map { |n| self.container.node_at n }.compact | |
end | |
def capture_state | |
@captured_live_neighbors = self.neighbors.select { |n| n.state == :on }.size | |
end | |
def evolve | |
case captured_live_neighbors | |
when 2; # do nothing | |
when 3; self.state = :on | |
else self.state = :off | |
end | |
end | |
def show | |
self.state == :on ? '*' : " " | |
end | |
private | |
def captured_live_neighbors | |
@captured_live_neighbors || [] | |
end | |
end | |
class Game | |
attr_reader :x, :y | |
def initialize(x, y) | |
@x = x | |
@y = y | |
build_grid | |
end | |
def build_grid | |
@grid = Array.new(y){ |xc| Array.new(x){ |yc| Node.new(xc, yc, self) }} | |
end | |
def randomize | |
@grid.each do |r| r.each do |c| c.tap { |n| n.state = rand > 0.8 ? :on : :off } end end; self | |
end | |
def node_at(point) | |
return unless point && point.x > 0 && point.y > 0 | |
@grid.fetch(point.x, [])[point.y] | |
end | |
def run(generations) | |
generations.times do | |
self.tick | |
puts self.show | |
end | |
end | |
def tick | |
@grid.each do |r| r.each do |c| c.capture_state end end | |
@grid.each do |r| r.each do |c| c.evolve end end | |
end | |
def show | |
@grid.map { |r| r.map { |n| n.show }.join('')}.join "\n" | |
end | |
end | |
describe Point do | |
it "returns an array of 8 neighbors" do | |
Point.new(0,0).neighbors.size.should be 8 | |
end | |
end | |
describe Game do | |
it "returns nil if node is out of range" do | |
g = Game.new 20, 20 | |
mock_point = mock :point, :x => -1, :y => -1 | |
g.node_at(mock_point).should be nil | |
end | |
end | |
describe Node do | |
context "that is alive" do | |
it "dies with fewer than 2 live neighbors" do | |
n = Node.new 3, 3, nil | |
n.state = :on | |
mock_node = mock :node, :state => :on | |
n.stub(:neighbors).and_return(Array.new(1, mock_node)) | |
n.capture_state | |
n.evolve | |
n.state.should be :off | |
end | |
it "lives with 2 or 3 live neighbors" do | |
n = Node.new 3, 3, nil | |
n.state = :on | |
mock_node = mock :node, :state => :on | |
n.stub(:neighbors).and_return(Array.new(2, mock_node)) | |
n.capture_state | |
n.evolve | |
n.state.should be :on | |
end | |
it "dies with more than 3 live neighbors" do | |
n = Node.new 3, 3, nil | |
n.state = :on | |
mock_node = mock :node, :state => :on | |
n.stub(:neighbors).and_return(Array.new(4, mock_node)) | |
n.capture_state | |
n.evolve | |
n.state.should be :off | |
end | |
end | |
context "that is dead" do | |
it "lives with 3 live neighbors" do | |
n = Node.new 3, 3, nil | |
n.state = :off | |
mock_node = mock :node, :state => :on | |
n.stub(:neighbors).and_return(Array.new(3, mock_node)) | |
n.capture_state | |
n.evolve | |
n.state.should be :on | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment