Skip to content

Instantly share code, notes, and snippets.

@DavidJRobertson
Last active August 29, 2015 13:58
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 DavidJRobertson/9945722 to your computer and use it in GitHub Desktop.
Save DavidJRobertson/9945722 to your computer and use it in GitHub Desktop.
Simple implementation of Conway's Game of Life
#! /usr/bin/env ruby
module LiveCell
def self.to_s
'o'
end
def self.next_generation(neighbours)
case neighbours.count(LiveCell)
when 2..3 then LiveCell
else DeadCell
end
end
end
module DeadCell
def self.to_s
'.'
end
def self.next_generation(neighbours)
case neighbours.count(LiveCell)
when 3 then LiveCell
else DeadCell
end
end
end
class Grid
attr_reader :xsize, :ysize
def initialize(x, y, default=nil)
@xsize = x
@ysize = y
@array = Array.new(y) { Array.new(x) { default } }
end
def get(coord)
x, y = wrap coord
@array.fetch(y).fetch(x)
end
def set(coord, value)
x, y = wrap coord
@array[y][x] = value
end
def each_cell(&block)
@array.each_with_index do |row, y|
row.each_with_index do |cell, x|
block.call cell, [x, y]
end
end
end
def neighbours(coord)
x, y = wrap coord
result = []
(y - 1).upto(y + 1) do |j|
(x - 1).upto(x + 1) do |i|
unless i == x and j == y
result << get([i, j])
end
end
end
result
end
def to_s
@array.reduce('') do |output, row|
output << row.reduce('') { |row, cell| row << cell.to_s } + "\n"
end
end
private
def wrap(coord)
x, y = coord
# Wrap coordinates
x %= @xsize
y %= @ysize
[x, y]
end
end
class Board
attr_accessor :grid
def initialize(xsize, ysize=nil)
ysize = xsize if ysize.nil?
@grid = Grid.new(xsize, ysize, DeadCell)
end
def randomize
prng = Random.new
@grid.each_cell do |cell, coord|
rand = prng.rand(100)
threshold = 10
# Biased towards DeadCells
@grid.set(coord, rand < threshold ? LiveCell : DeadCell)
end
puts @grid.to_s
end
def parse(input)
input.strip!
xsize = input.lines.first.length - 1
ysize = input.lines.count
@grid = Grid.new(xsize, ysize)
input.each_line.with_index do |line, y|
line.strip!
raise "Invalid input board" if line.length != xsize
line.each_char.with_index do |char, x|
cell = (char == LiveCell.to_s) ? LiveCell : DeadCell
@grid.set([x, y], cell)
end
end
end
def next_generation
newgrid = @grid.dup
@grid.each_cell do |cell, coord|
neighbours = @grid.neighbours(coord)
new_cell = cell.next_generation(neighbours)
newgrid.set(coord, new_cell)
end
@grid = newgrid
end
end
def run!
xsize = 90
ysize = 30
if ARGV.length == 2
xsize = ARGV[0].to_i
ysize = ARGV[1].to_i
end
board = Board.new(xsize, ysize)
if ARGV.length == 1
board.parse(File.read(ARGV[0]))
else
board.randomize
end
generation = 0
loop do
print "\e[H\e[2J" # Clear console
puts "Generation #{generation += 1}"
puts board.grid.to_s
board.next_generation
sleep 0.25
end
end
run! if __FILE__==$0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment