Skip to content

Instantly share code, notes, and snippets.

@iamvery
Last active August 29, 2015 14:01
Show Gist options
  • Save iamvery/d56fd1dfc1d2644cdeb0 to your computer and use it in GitHub Desktop.
Save iamvery/d56fd1dfc1d2644cdeb0 to your computer and use it in GitHub Desktop.
Conway's Game of Life, written in Ruby

Conway's Game of Life, written in Ruby

Run the game

ruby driver.rb

Run the specs

rspec game_of_life_spec.rb
def tick(grid)
n = grid.flat_map{ |c| neighbors(*c) }
cells = grid | n
cells.reduce(grid) do |new_grid, cell|
if grid.include?(cell)
new_grid & kill(cell, grid)
else
new_grid | birth(cell, grid) - grid
end
end
end
def neighbors(x,y)
range = (-1..1).to_a
offsets = range.product(range)
offsets.delete([0,0])
offsets.map do |(ox,oy)|
[x-ox, y-oy]
end
end
def living_neighbors(cell, grid)
neighbors(*cell).select do |n|
grid.include?(n)
end
end
def kill(cell, grid)
living_neighbors = living_neighbors(cell, grid)
grid.dup.tap do |g|
if living_neighbors.length < 2 || living_neighbors.length > 3
g.delete(cell)
end
end
end
def birth(cell, grid)
living_neighbors = living_neighbors(cell, grid)
grid.dup.tap do |g|
if living_neighbors.length == 3
g << cell
end
end
end
require 'set'
require_relative 'conway'
require_relative 'game_of_life_renderer'
grid = Set[
[0,1], [1,1], [2,1] # blinker
#[1,0], [2,1], [0,2], [1,2], [2,2] # glider
#[1,1], [1,2], [1,3], [2,0], [2,1], [2,2] # toad
]
renderer = GameOfLifeRenderer.new(10,10)
while true
renderer.render_grid(grid)
grid = tick(grid)
sleep(1)
end
class GameOfLifeRenderer
attr_reader :width, :height, :io
def initialize(width, height, io = $stdout)
@width, @height = width, height
@io = io
end
def render_grid(grid)
clear_screen
width.times do |x|
height.times do |y|
render_coord([x, y], grid)
end
io.puts
end
io.flush
end
private
def render_coord(coord, grid)
if grid.include?(coord)
io.print('0')
else
io.print('.')
end
end
def clear_screen
io.puts("\e[H\e[2J")
end
end
require_relative 'conway'
describe 'game of life' do
it 'works for blinker' do
# x x x
# o o o
# x x x
grid_before = [[0,1], [1,1], [2,1]]
# x o x
# x o x
# x o x
grid_after = [[1,0], [1,1], [1,2]]
expect(tick(grid_before)).to match_array(grid_after)
end
describe 'kill' do
it 'kills cell with less than 2 neighbors' do
cell = [0,0]
grid_before = [cell]
expect(kill(cell, grid_before)).to eq([])
end
it 'kills cell with more than 3 neighbors' do
cell = [1,1]
# o o o
# o 0 x
grid_before = [[0,0], [0,1], [0,2], [1,0], cell]
grid_after = [[0,0], [0,1], [0,2], [1,0]]
expect(kill(cell, grid_before)).to match_array(grid_after)
end
it 'does nothing with cell having 2 neighbors' do
cell = [0,0]
# 0 o
# o x
grid_before = [cell, [0,1], [1,0]]
expect(kill(cell, grid_before)).to match_array(grid_before)
end
it 'does nothing with cell having 3 neighbors' do
cell = [0,0]
# 0 o
# o o
grid_before = [cell, [0,1], [1,0], [1,1]]
expect(kill(cell, grid_before)).to match_array(grid_before)
end
end
describe 'birth' do
it 'births cell with exactly 3 neighbors' do
cell = [0,0]
# x o
# o o
grid_before = [[1,0], [0,1], [1,1]]
grid_after = [[1,0], [0,1], [1,1], cell]
expect(birth(cell, grid_before)).to match_array(grid_after)
end
it 'does nothing with cell having less than 3 neighbors' do
cell = [0,0]
grid_before = []
expect(birth(cell, grid_before)).to eq([])
end
it 'does nothing with cell having more than 3 neighbors' do
cell = [1,1]
# o o o
# o 0 x
grid_before = [[0,0], [0,1], [0,2], [1,0]]
expect(birth(cell, grid_before)).to match_array(grid_before)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment