Created
July 19, 2012 10:33
-
-
Save perspectivezoom/3142930 to your computer and use it in GitHub Desktop.
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
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 |
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
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