Last active
August 29, 2015 14:09
-
-
Save mvlwn/1b08b2d142eb6b8d0ff5 to your computer and use it in GitHub Desktop.
Tijn's Game of Life
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
#!/usr/bin/env ruby | |
module Printer | |
def print(str) | |
puts str | |
end | |
end | |
class Game | |
include Printer | |
def initialize(size = 5, rounds = 2) | |
@size = size.to_i | |
@rounds = rounds.to_i | |
@world = World.new(@size) | |
@current_round = 1 | |
end | |
def seed(alive_cell_coordinates = [[]]) | |
@world.seed_life(alive_cell_coordinates) | |
end | |
def random_seeds | |
@world.seed_random_life | |
end | |
def start | |
print "Starting Tijn's Game of Life" | |
print "We live in a #{@size}x#{@size} world and we play #{@rounds} rounds" | |
@world.print_world | |
@rounds.times{ self.play_round } | |
end | |
def play_round | |
system('clear') | |
# print "--------------------------------------------" | |
# print "Tijn's Game of Life" | |
# print "Playing round #{@current_round}" | |
@world.annual_foresight | |
@world.next_year | |
@world.print_world | |
sleep 0.05 | |
@current_round += 1 | |
end | |
end | |
class World | |
include Printer | |
def initialize(size) | |
@size = size | |
@grid = create_grid | |
end | |
def seed_life(alive_cell_coordinates) | |
alive_cell_coordinates.each do |coordinates| | |
x = coordinates[0] | |
y = coordinates[1] | |
cell = @grid[x][y] | |
cell.give_life | |
print "Seeding cell #{cell.inspect} with life" | |
end | |
end | |
def seed_random_life | |
@grid.flatten.each{|cell| cell.give_life if [0,0,1].sample == 1 } | |
end | |
def annual_foresight | |
@grid.flatten.each{|cell| set_prospect_for(cell) } | |
end | |
def next_year | |
@grid.flatten.each{|cell| cell.call_prospect } | |
end | |
def print_world | |
print @grid.collect{|row| row.collect{|c| "#{c.alive? ? c.symbol : ' '}" }.join(' ') }.join("\n") | |
end | |
private | |
def create_grid | |
@size.times.collect do |x| | |
@size.times.collect do |y| | |
Cell.new(x, y) | |
end | |
end | |
end | |
def set_prospect_for(cell) | |
alive_neighbours = alive_neighbours_of(cell).size | |
dead_neighbours = dead_neighbours_of(cell).size | |
# Any live cell with fewer than two live neighbours dies, as if by needs caused by underpopulation. | |
# Any live cell with more than three live neighbours dies, as if by overcrowding. | |
if cell.alive? && (alive_neighbours < 2 || alive_neighbours > 3) | |
cell.prospect = :death | |
# Any live cell with two or three live neighbours lives, unchanged, to the next generation. | |
elsif cell.alive? && [2,3].include?(alive_neighbours) | |
# Any dead cell with exactly three live neighbours cells will come to life. | |
cell.prospect = :none | |
elsif cell.dead? && alive_neighbours == 3 | |
cell.prospect = :birth | |
else | |
cell.prospect = :none | |
end | |
end | |
def alive_neighbours_of(cell) | |
neighbours_of(cell).select{|neighbour| neighbour.alive? } | |
end | |
def dead_neighbours_of(cell) | |
neighbours_of(cell).select{|neighbour| neighbour.dead? } | |
end | |
def neighbours_of(cell) | |
max = @size - 1 | |
neighbours = [] | |
neighbours << @grid[cell.x-1][cell.y-1] if cell.x > 0 && cell.y > 0 | |
neighbours << @grid[cell.x] [cell.y-1] if cell.y > 0 | |
neighbours << @grid[cell.x+1][cell.y-1] if cell.x < max && cell.y > 0 | |
neighbours << @grid[cell.x-1][cell.y] if cell.x > 0 | |
neighbours << @grid[cell.x+1][cell.y] if cell.x < max | |
neighbours << @grid[cell.x-1][cell.y+1] if cell.x > 0 && cell.y < max | |
neighbours << @grid[cell.x] [cell.y+1] if cell.y < max | |
neighbours << @grid[cell.x+1][cell.y+1] if cell.x < max && cell.y < max | |
neighbours | |
end | |
end | |
class Cell | |
attr_reader :x, :y, :age | |
attr_accessor :prospect | |
def initialize(x, y) | |
@x = x | |
@y = y | |
@alive = false | |
@prospect = :none | |
@age = 0 | |
end | |
def give_life | |
@alive = true | |
end | |
def alive? | |
@alive | |
end | |
def dead? | |
!@alive | |
end | |
def symbol | |
if alive? | |
if age > 3 | |
'o' | |
elsif age > 1 | |
'-' | |
else | |
'.' | |
end | |
else | |
' ' | |
end | |
end | |
def call_prospect | |
if alive? && @prospect == :death | |
@alive = false | |
@age = 0 | |
elsif dead? && @prospect == :birth | |
@alive = true | |
@age = 0 | |
elsif @prospect == :none | |
if alive? | |
@age += 1 | |
end | |
else | |
raise "Your prospect #{@prospect} is impossible for your #{@alive} state" | |
end | |
end | |
end | |
size = ENV['SIZE'] || 100 | |
rounds = ENV['ROUNDS'] || 400 | |
game = Game.new(size, rounds) | |
# north_west_glider = [[2,1], [3,2], [1,3], [2,3], [3,3]] | |
# south_east_glider = [[14,15], [14,14], [13,13], [14,13], [15,13]] | |
# game.seed(north_west_glider) | |
# game.seed(north_west_glider.collect{|i| i.collect{|j| j+6 } }) | |
# game.seed(south_east_glider) | |
# game.seed([[20,2], [21,2], [22,2]]) | |
# game.seed([[2,20], [2,21], [2,22]]) | |
game.random_seeds | |
game.start |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Run game.rb from your terminal