Skip to content

Instantly share code, notes, and snippets.

@perspectivezoom
Created July 19, 2012 10:33
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save perspectivezoom/3142930 to your computer and use it in GitHub Desktop.
Save perspectivezoom/3142930 to your computer and use it in GitHub Desktop.
class Position
attr_reader :x, :y
@cache_of_positions = {}
def self.new_with_memo(x,y)
@cache_of_positions[[x,y]] || Position.new(x,y).tap do |instance|
@cache_of_positions[[x,y]] = instance
end
end
def initialize(x,y)
@x = x
@y = y
end
def to_a
[@x, @y]
end
def to_s
"P(#{@x},#{@y})"
end
def neighbors
return @cached_neighbors if @cached_neighbors
ar = []
(-1..1).each do |x|
(-1..1).each do |y|
ar << Position.new_with_memo(x + @x, y + @y) unless x == 0 && y == 0
end
end
@cached_neighbors = ar
return ar
end
end
class Board
attr_reader :cells
@@print_board_board_size = 40
def self.from_coordinate_pair_ar(coord_ar)
Board.new(coord_ar.map{ |x,y| Position.new_with_memo(x,y) })
end
def self.from_string(str)
Board.from_coordinate_pair_ar(str_to_coordinate_pair_ar(str))
end
def initialize(ar_of_positions)
@generation = 0
@live_cells = ar_of_positions.uniq
end
def run
while true
print to_s
sleep 0.05
advance_to_next_generation!
end
end
def advance_to_next_generation!
next_gen_live_cells = []
hash_of_positions_with_number_of_live_neighbors.each do |pos, num_live_neighbors|
next_gen_live_cells << pos if num_live_neighbors == 3 || (num_live_neighbors == 2 && @live_cells.include?(pos))
end
@live_cells = next_gen_live_cells
@generation += 1
end
def to_s
ar = []
@@print_board_board_size.times do
ar << Array.new(@@print_board_board_size, ' ')
end
@live_cells.each do |pos|
if (0..@@print_board_board_size-1).include?(pos.x) && (0..@@print_board_board_size-1).include?(pos.y)
ar[pos.x][pos.y] = 'X'
end
end
"Generation: #{@generation}\n" + ar.map { |a| a.join + "\n"}.join
end
private
def self.str_to_coordinate_pair_ar(str)
input_ar = str.split(' ')
output = []
while !input_ar.empty?
x = input_ar.shift.to_i
y = input_ar.shift.to_i
output << [x,y]
end
return output
end
def hash_of_positions_with_number_of_live_neighbors
neighbors_ar = @live_cells.map { |pos| pos.neighbors }
neighbors_ar.flatten.inject( Hash.new(0) ) do |memo, pos|
memo[pos] = memo[pos] + 1
memo
end
end
end
# # Initial Glider Position: http://www.conwaylife.com/patterns/gosperglidergun.cells
# # 1234567890123456789012345678901234567890
# # 1 ........................O
# # 2 ......................O.O
# # 3 ............OO......OO............OO
# # 4 ...........O...O....OO............OO
# # 5 OO........O.....O...OO
# # 6 OO........O...O.OO....O.O
# # 7 ..........O.....O.......O
# # 8 ...........O...O
# # 9 ............OO
glider = Board.from_string '1 25 2 23 2 25 3 13 3 14 3 21 3 22 3 35 3 36 4 12 4 16 4 21 4 22 4 35 4 36 5 1 5 2 5 11 5 17 5 21 5 22 6 1 6 2 6 11 6 15 6 17 6 18 6 23 6 25 7 11 7 17 7 25 8 12 8 16 9 13 9 14'
glider.run
require 'rspec'
describe 'Position' do
let(:pos) { pos = Position.new_with_memo(1,2) }
describe '.new_with_memo' do
it 'returns a cached instance of a position instead of creating a new one when given has the exact same coordinates' do
pos2 = Position.new_with_memo(1,2)
pos.should equal pos2
end
end
describe '#to_a' do
it 'outputs an array of the Positions coordinates' do
pos.to_a.should eq [1,2]
end
end
describe '#neighbors' do
it 'returns an array of neighboring positions' do
expected = [[0,1],[0,2],[0,3],[1,1],[1,3],[2,1],[2,2],[2,3]].sort
pos.neighbors.map { |p| p.to_a }.sort.should eq expected
end
end
end
describe 'Board' do
let(:board) { Board.from_string("1 2 2 2 3 2")}
describe '#positions_of(cells_ar)' do
it 'takes an array of cells and returns an array of their Position objects' do
board.cells.map { |position| position.to_a }.should eq [[1,2],[2,2],[3,2]]
end
end
describe '#advance_to_next_generation!' do
it 'correctly updates @cells to reflect the next generation of live cells' do
board.advance_to_next_generation!
board.cells.map { |position| position.to_a }.sort.should eq [[2,1],[2,2],[2,3]]
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment