conway 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +3 -3
- data/bin/conway +2 -2
- data/lib/conway.rb +1 -0
- data/lib/conway/cell_location_lookup.rb +35 -0
- data/lib/conway/cell_space.rb +1 -1
- data/lib/conway/driver/ascii.rb +78 -0
- data/lib/conway/generation.rb +32 -7
- data/lib/conway/point.rb +1 -0
- data/lib/conway/potential_cell_collection.rb +25 -18
- data/spec/conway/cell_location_lookup_spec.rb +90 -0
- data/spec/conway/cell_space_spec.rb +2 -2
- data/spec/conway/generation_spec.rb +11 -0
- data/spec/conway/point_spec.rb +4 -0
- data/spec/conway/potential_cell_collection_spec.rb +39 -5
- metadata +9 -10
- data/lib/conway/visualizer/ascii.rb +0 -69
data/README.md
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
## Conway
|
2
2
|
A simple Game of Life implementation with foremost focus on object design.
|
3
3
|
|
4
|
-
It's currently
|
5
|
-
|
4
|
+
It's currently a bit leaky of object references and has not had efficiency
|
5
|
+
optimization.
|
6
6
|
|
7
7
|
Conway comes with a very simple ASCII visualizer. It can be invoked as
|
8
8
|
below, where the size argument determines the dimensions of the cell grid:
|
9
9
|
|
10
|
-
conway --size 25 --cells="2,3
|
10
|
+
conway --size 25 --cells="10,2 9,3 8,3 9,4 10,4"
|
11
11
|
conway -s 30 -c 2,3:3,3:3,2:2,2:3,4
|
12
12
|
|
13
13
|
Please feel free to send feedback via the
|
data/bin/conway
CHANGED
@@ -5,7 +5,7 @@ lib_dir = File.join(File.dirname(__FILE__), '..', 'lib')
|
|
5
5
|
$LOAD_PATH.unshift lib_dir if File.directory?(lib_dir)
|
6
6
|
|
7
7
|
require 'choice'
|
8
|
-
require 'conway/
|
8
|
+
require 'conway/driver/ascii'
|
9
9
|
|
10
10
|
PROGRAM_VERSION = 1
|
11
11
|
|
@@ -69,7 +69,7 @@ Signal.trap("INT") do
|
|
69
69
|
end
|
70
70
|
|
71
71
|
live_points = ConwayCli.parse_points Choice[:cells]
|
72
|
-
grid = Conway::
|
72
|
+
grid = Conway::Driver::Ascii.new(Choice[:size], live_points)
|
73
73
|
|
74
74
|
grid.loop do |step|
|
75
75
|
puts step
|
data/lib/conway.rb
CHANGED
@@ -0,0 +1,35 @@
|
|
1
|
+
module Conway
|
2
|
+
class CellLocationLookup
|
3
|
+
def initialize
|
4
|
+
@hash ||= {}
|
5
|
+
@point ||= Point.new(0,0)
|
6
|
+
end
|
7
|
+
|
8
|
+
def insert(cell_location)
|
9
|
+
@hash[cell_location.point] = cell_location
|
10
|
+
end
|
11
|
+
|
12
|
+
def retrieve(point_or_x, y=nil)
|
13
|
+
if y
|
14
|
+
point_or_x = @point.update(point_or_x, y)
|
15
|
+
end
|
16
|
+
@hash[point_or_x]
|
17
|
+
end
|
18
|
+
|
19
|
+
def locations
|
20
|
+
@hash.values
|
21
|
+
end
|
22
|
+
|
23
|
+
def count
|
24
|
+
locations.count
|
25
|
+
end
|
26
|
+
|
27
|
+
def empty?
|
28
|
+
!(count > 0)
|
29
|
+
end
|
30
|
+
|
31
|
+
def each(&block)
|
32
|
+
locations.each(&block)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/conway/cell_space.rb
CHANGED
@@ -0,0 +1,78 @@
|
|
1
|
+
require "conway"
|
2
|
+
|
3
|
+
module Conway
|
4
|
+
module Driver
|
5
|
+
class Ascii
|
6
|
+
def initialize(size, starting_cells, loop_interval=0.25)
|
7
|
+
self.max_x = self.max_y = size
|
8
|
+
self.starting_cells = starting_cells
|
9
|
+
self.loop_interval = loop_interval
|
10
|
+
end
|
11
|
+
|
12
|
+
def loop
|
13
|
+
generation = Generation.new(starting_cells)
|
14
|
+
start = Time.now
|
15
|
+
|
16
|
+
puts "They live!!\n\n"
|
17
|
+
|
18
|
+
begin
|
19
|
+
lookup = generation.location_lookup
|
20
|
+
|
21
|
+
grid = generate_grid(lookup)
|
22
|
+
|
23
|
+
grid << current_stats(lookup)
|
24
|
+
grid << elapsed_time_since(start)
|
25
|
+
|
26
|
+
|
27
|
+
yield grid if block_given?
|
28
|
+
|
29
|
+
if lookup.empty?
|
30
|
+
puts "\nThey have all perished! D-:"
|
31
|
+
break
|
32
|
+
end
|
33
|
+
|
34
|
+
sleep(loop_interval)
|
35
|
+
end while(generation = generation.next)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
attr_accessor :max_x, :max_y, :starting_cells, :loop_interval
|
40
|
+
|
41
|
+
def generate_grid(lookup)
|
42
|
+
grid = ""
|
43
|
+
(1..max_y).each do |y|
|
44
|
+
(1..max_x).each do |x|
|
45
|
+
cell_char = cell_content_for(lookup, x, y)
|
46
|
+
grid << "|#{cell_char}"
|
47
|
+
end
|
48
|
+
grid << "|\n"
|
49
|
+
end
|
50
|
+
grid
|
51
|
+
end
|
52
|
+
|
53
|
+
def cell_content_for(lookup, x,y)
|
54
|
+
lookup.retrieve(x,y) ? "X" : " "
|
55
|
+
end
|
56
|
+
|
57
|
+
def current_stats(lookup)
|
58
|
+
stats = "Total objects: #{live_object_count} "
|
59
|
+
stats << "Total living cells: #{lookup.count}\n"
|
60
|
+
end
|
61
|
+
|
62
|
+
def elapsed_time_since(start)
|
63
|
+
elapsed_minutes, elapsed_seconds = ((Time.now - start).to_i).divmod 60
|
64
|
+
"Elapsed time: #{elapsed_minutes} min, #{elapsed_seconds} secs\n"
|
65
|
+
end
|
66
|
+
|
67
|
+
def live_object_count
|
68
|
+
if ObjectSpace.respond_to?(:count_objects)
|
69
|
+
# Ruby 1.9.2
|
70
|
+
ObjectSpace.count_objects[:TOTAL]
|
71
|
+
else
|
72
|
+
# Ruby 1.8.7
|
73
|
+
ObjectSpace.live_objects
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/conway/generation.rb
CHANGED
@@ -1,16 +1,41 @@
|
|
1
1
|
module Conway
|
2
2
|
class Generation
|
3
|
-
attr_reader :
|
3
|
+
attr_reader :location_lookup
|
4
4
|
|
5
|
-
def initialize(
|
6
|
-
|
7
|
-
|
5
|
+
def initialize(cell_locations, rule_set=RuleSet.new)
|
6
|
+
self.location_lookup = normalize_to_lookup cell_locations
|
7
|
+
self.rule_set = rule_set
|
8
8
|
end
|
9
9
|
|
10
10
|
def next
|
11
|
-
cell_space
|
12
|
-
|
13
|
-
Generation.new
|
11
|
+
cell_space = CellSpace.new(cell_coordinates)
|
12
|
+
cell_lookup = cell_space.apply(rule_set)
|
13
|
+
Generation.new cell_lookup, rule_set
|
14
|
+
end
|
15
|
+
|
16
|
+
def cell_coordinates
|
17
|
+
location_lookup.locations.map {|loc| loc.point }
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
attr_accessor :rule_set
|
22
|
+
attr_writer :location_lookup
|
23
|
+
|
24
|
+
def normalize_to_lookup(points)
|
25
|
+
return points unless points.kind_of?(Array)
|
26
|
+
|
27
|
+
lookup = CellLocationLookup.new
|
28
|
+
points.each do |point|
|
29
|
+
loc = point_to_location(point)
|
30
|
+
lookup.insert(loc)
|
31
|
+
end
|
32
|
+
|
33
|
+
lookup
|
34
|
+
end
|
35
|
+
|
36
|
+
def point_to_location(point)
|
37
|
+
@live_cell ||= LiveCell.new
|
38
|
+
CellLocation.new(@live_cell, point)
|
14
39
|
end
|
15
40
|
end
|
16
41
|
end
|
data/lib/conway/point.rb
CHANGED
@@ -1,45 +1,52 @@
|
|
1
1
|
module Conway
|
2
2
|
class PotentialCellCollection
|
3
|
+
attr_reader :live_cell_lookup
|
4
|
+
|
3
5
|
def initialize(live_locations)
|
6
|
+
self.live_cell_lookup = CellLocationLookup.new
|
7
|
+
self.potential_cell_lookup = CellLocationLookup.new
|
8
|
+
self.default_dead_cell = DeadCell.new
|
9
|
+
|
4
10
|
identify_potential_locations(live_locations)
|
5
11
|
end
|
6
12
|
|
7
13
|
def each_cell(&block)
|
8
|
-
|
9
|
-
|
10
|
-
neighbor_cells = neighbors.map {|n| n.cell }
|
14
|
+
potential_cell_lookup.each do |cell_location|
|
15
|
+
neighbor_cells = neighbor_cells_for(cell_location)
|
11
16
|
|
12
|
-
|
17
|
+
next_cell = block.call(cell_location.cell, neighbor_cells)
|
13
18
|
|
14
|
-
|
15
|
-
|
19
|
+
if next_cell.alive?
|
20
|
+
live_cell_lookup.insert(cell_location)
|
21
|
+
end
|
16
22
|
end
|
17
23
|
end
|
18
24
|
|
19
|
-
def live_cell_locations
|
20
|
-
potential_cell_locations.values.select{|loc| loc.cell.kind_of?(LiveCell) }
|
21
|
-
end
|
22
|
-
|
23
25
|
private
|
24
|
-
|
25
|
-
|
26
|
-
CellLocation.new(DeadCell.new, point)
|
27
|
-
end
|
28
|
-
end
|
26
|
+
attr_accessor :potential_cell_lookup, :default_dead_cell
|
27
|
+
attr_writer :live_cell_lookup
|
29
28
|
|
30
29
|
def identify_potential_locations(locations)
|
31
30
|
locations.each do |loc|
|
32
|
-
|
31
|
+
potential_cell_lookup.insert(loc)
|
33
32
|
neighbors_for(loc).each do |neighbor|
|
34
|
-
|
33
|
+
potential_cell_lookup.insert(neighbor)
|
35
34
|
end
|
36
35
|
end
|
37
36
|
end
|
38
37
|
|
38
|
+
def dead_cell_location(point)
|
39
|
+
CellLocation.new(default_dead_cell, point)
|
40
|
+
end
|
41
|
+
|
39
42
|
def neighbors_for(location)
|
40
43
|
location.adjacent_points.map do |point|
|
41
|
-
|
44
|
+
potential_cell_lookup.retrieve(point) || dead_cell_location(point)
|
42
45
|
end
|
43
46
|
end
|
47
|
+
|
48
|
+
def neighbor_cells_for(location)
|
49
|
+
neighbors_for(location).map {|n| n.cell }
|
50
|
+
end
|
44
51
|
end
|
45
52
|
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
include Conway
|
4
|
+
|
5
|
+
describe CellLocationLookup do
|
6
|
+
let(:point) { Point.new 1,1 }
|
7
|
+
let(:cell) { LiveCell.new }
|
8
|
+
let(:location) { CellLocation.new cell, point }
|
9
|
+
let(:lookup) { CellLocationLookup.new }
|
10
|
+
|
11
|
+
describe "#insert" do
|
12
|
+
it "accepts a CellLocation" do
|
13
|
+
lookup.insert location
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#retrieve" do
|
18
|
+
before { lookup.insert location }
|
19
|
+
|
20
|
+
it "looks up based on a point" do
|
21
|
+
lookup.retrieve(point).should eql(location)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "looks up based on x,y" do
|
25
|
+
lookup.retrieve(1,1).should eql(location)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#each" do
|
30
|
+
let(:point2) { Point.new 2,2 }
|
31
|
+
let(:location2) { CellLocation.new cell, point2 }
|
32
|
+
|
33
|
+
before do
|
34
|
+
lookup.insert location
|
35
|
+
lookup.insert location2
|
36
|
+
end
|
37
|
+
|
38
|
+
it "yields each location once" do
|
39
|
+
locations = []
|
40
|
+
lookup.each do |loc|
|
41
|
+
locations << loc
|
42
|
+
end
|
43
|
+
|
44
|
+
locations.should have(2).locations
|
45
|
+
locations.should include(location)
|
46
|
+
locations.should include(location2)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#locations" do
|
51
|
+
let(:point2) { Point.new 2,2 }
|
52
|
+
let(:location2) { CellLocation.new cell, point2 }
|
53
|
+
|
54
|
+
before do
|
55
|
+
lookup.insert location
|
56
|
+
lookup.insert location2
|
57
|
+
end
|
58
|
+
|
59
|
+
it "is all the contained locations" do
|
60
|
+
lookup.locations.should have(2).locations
|
61
|
+
lookup.locations.should include(location)
|
62
|
+
lookup.locations.should include(location2)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#count" do
|
67
|
+
let(:point2) { Point.new 2,2 }
|
68
|
+
let(:location2) { CellLocation.new cell, point2 }
|
69
|
+
|
70
|
+
before do
|
71
|
+
lookup.insert location
|
72
|
+
lookup.insert location2
|
73
|
+
end
|
74
|
+
|
75
|
+
it "is the number of contained locations" do
|
76
|
+
lookup.count.should == 2
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "#empty?" do
|
81
|
+
context "when the count is 0" do
|
82
|
+
it { should be_empty }
|
83
|
+
end
|
84
|
+
|
85
|
+
context "when the count is 1" do
|
86
|
+
before { subject.insert location }
|
87
|
+
it { should_not be_empty }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -11,8 +11,8 @@ describe CellSpace do
|
|
11
11
|
let(:space) { CellSpace.new [Point.new(0,0)] }
|
12
12
|
let(:rule_set) { RuleSet.new }
|
13
13
|
|
14
|
-
it "returns a
|
15
|
-
space.apply(rule_set).
|
14
|
+
it "returns a CellLocationLookup" do
|
15
|
+
space.apply(rule_set).should be_a_kind_of(CellLocationLookup)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -6,6 +6,17 @@ describe Generation do
|
|
6
6
|
let(:coordinates) { [Point.new(0,0), Point.new(1,1)] }
|
7
7
|
let(:generation) { Generation.new(coordinates) }
|
8
8
|
|
9
|
+
describe "#initialize" do
|
10
|
+
it "accepts an array of Points" do
|
11
|
+
expect { generation.next }.to_not raise_error
|
12
|
+
end
|
13
|
+
|
14
|
+
it "accepts a CellLocationLookup" do
|
15
|
+
generation = Generation.new(CellLocationLookup.new)
|
16
|
+
expect { generation.next }.to_not raise_error
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
9
20
|
describe "#cell_coordinates" do
|
10
21
|
it "returns points of current live cells" do
|
11
22
|
generation.cell_coordinates.should have(2).points
|
data/spec/conway/point_spec.rb
CHANGED
@@ -5,7 +5,8 @@ include Conway
|
|
5
5
|
describe PotentialCellCollection do
|
6
6
|
let(:live_cell) { LiveCell.new }
|
7
7
|
let(:point) { Point.new(1,1) }
|
8
|
-
let(:
|
8
|
+
let(:cell_location) { CellLocation.new(live_cell, point) }
|
9
|
+
let(:initial_cells) { [cell_location] }
|
9
10
|
let(:collection) { PotentialCellCollection.new(initial_cells) }
|
10
11
|
|
11
12
|
describe "#each_cell" do
|
@@ -18,11 +19,38 @@ describe PotentialCellCollection do
|
|
18
19
|
yielded_cells.should include(live_cell)
|
19
20
|
end
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
22
|
+
context "when the cell is a LiveCell" do
|
23
|
+
it "does not retain the cell if it becomes a DeadCell" do
|
24
|
+
collection.each_cell do |cell, neighbors|
|
25
|
+
DeadCell.new
|
26
|
+
end
|
27
|
+
collection.live_cell_lookup.should be_empty
|
28
|
+
end
|
29
|
+
|
30
|
+
it "retains the cell if it remains a LiveCell" do
|
31
|
+
collection.each_cell do |cell, neighbors|
|
32
|
+
LiveCell.new
|
33
|
+
end
|
34
|
+
collection.live_cell_lookup.locations.should include(cell_location)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when the cell is a DeadCell" do
|
39
|
+
let(:cell_location) { CellLocation.new(DeadCell.new, point) }
|
40
|
+
|
41
|
+
it "does not retain the cell if it remains a DeadCell" do
|
42
|
+
collection.each_cell do |cell, neighbors|
|
43
|
+
DeadCell.new
|
44
|
+
end
|
45
|
+
collection.live_cell_lookup.should be_empty
|
46
|
+
end
|
47
|
+
|
48
|
+
it "retains the cell if it remains a LiveCell" do
|
49
|
+
collection.each_cell do |cell, neighbors|
|
50
|
+
LiveCell.new
|
51
|
+
end
|
52
|
+
collection.live_cell_lookup.locations.should include(cell_location)
|
24
53
|
end
|
25
|
-
collection.live_cell_locations.should be_empty
|
26
54
|
end
|
27
55
|
|
28
56
|
context "neighbors" do
|
@@ -53,7 +81,13 @@ describe PotentialCellCollection do
|
|
53
81
|
end
|
54
82
|
|
55
83
|
it "includes all neighboring DeadCells" do
|
84
|
+
yielded_neighbors = nil
|
85
|
+
collection.each_cell do |cell, neighbors|
|
86
|
+
yielded_neighbors = neighbors
|
87
|
+
break
|
88
|
+
end
|
56
89
|
|
90
|
+
(yielded_neighbors - [neighbor_cell]).any?{|c| c.alive?}.should be_false
|
57
91
|
end
|
58
92
|
end
|
59
93
|
end
|
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: conway
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: 25
|
5
4
|
prerelease: false
|
6
5
|
segments:
|
7
6
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: 0.2.0
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Matt Yoho
|
@@ -15,7 +14,7 @@ autorequire:
|
|
15
14
|
bindir: bin
|
16
15
|
cert_chain: []
|
17
16
|
|
18
|
-
date: 2011-01-
|
17
|
+
date: 2011-01-21 00:00:00 -05:00
|
19
18
|
default_executable: conway
|
20
19
|
dependencies:
|
21
20
|
- !ruby/object:Gem::Dependency
|
@@ -26,7 +25,6 @@ dependencies:
|
|
26
25
|
requirements:
|
27
26
|
- - "="
|
28
27
|
- !ruby/object:Gem::Version
|
29
|
-
hash: 19
|
30
28
|
segments:
|
31
29
|
- 0
|
32
30
|
- 1
|
@@ -47,15 +45,17 @@ files:
|
|
47
45
|
- MIT-LICENSE
|
48
46
|
- README.md
|
49
47
|
- lib/conway/cell_location.rb
|
48
|
+
- lib/conway/cell_location_lookup.rb
|
50
49
|
- lib/conway/cell_space.rb
|
51
50
|
- lib/conway/dead_cell.rb
|
51
|
+
- lib/conway/driver/ascii.rb
|
52
52
|
- lib/conway/generation.rb
|
53
53
|
- lib/conway/live_cell.rb
|
54
54
|
- lib/conway/point.rb
|
55
55
|
- lib/conway/potential_cell_collection.rb
|
56
56
|
- lib/conway/rule_set.rb
|
57
|
-
- lib/conway/visualizer/ascii.rb
|
58
57
|
- lib/conway.rb
|
58
|
+
- spec/conway/cell_location_lookup_spec.rb
|
59
59
|
- spec/conway/cell_location_spec.rb
|
60
60
|
- spec/conway/cell_space_spec.rb
|
61
61
|
- spec/conway/dead_cell_spec.rb
|
@@ -80,7 +80,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
80
80
|
requirements:
|
81
81
|
- - ">="
|
82
82
|
- !ruby/object:Gem::Version
|
83
|
-
hash: 3
|
84
83
|
segments:
|
85
84
|
- 0
|
86
85
|
version: "0"
|
@@ -89,7 +88,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
89
88
|
requirements:
|
90
89
|
- - ">="
|
91
90
|
- !ruby/object:Gem::Version
|
92
|
-
hash: 3
|
93
91
|
segments:
|
94
92
|
- 0
|
95
93
|
version: "0"
|
@@ -99,8 +97,9 @@ rubyforge_project:
|
|
99
97
|
rubygems_version: 1.3.7
|
100
98
|
signing_key:
|
101
99
|
specification_version: 3
|
102
|
-
summary: A simple implementation of Conway's Game of Life with an ASCII visualizer . This version has significant reference leaks.
|
100
|
+
summary: A simple implementation of Conway's Game of Life with an ASCII visualizer . This version has fewer significant reference leaks.
|
103
101
|
test_files:
|
102
|
+
- spec/conway/cell_location_lookup_spec.rb
|
104
103
|
- spec/conway/cell_location_spec.rb
|
105
104
|
- spec/conway/cell_space_spec.rb
|
106
105
|
- spec/conway/dead_cell_spec.rb
|
@@ -1,69 +0,0 @@
|
|
1
|
-
require "conway"
|
2
|
-
|
3
|
-
module Conway
|
4
|
-
module Visualizer
|
5
|
-
class Ascii
|
6
|
-
def initialize(size, starting_cells, loop_interval=0.25)
|
7
|
-
self.max_x = self.max_y = size
|
8
|
-
self.starting_cells = starting_cells
|
9
|
-
self.loop_interval = loop_interval
|
10
|
-
end
|
11
|
-
|
12
|
-
def loop
|
13
|
-
generation = Generation.new(starting_cells)
|
14
|
-
start = Time.now
|
15
|
-
|
16
|
-
puts "They live!!\n\n"
|
17
|
-
|
18
|
-
begin
|
19
|
-
live_cells = generation.cell_coordinates
|
20
|
-
|
21
|
-
if live_cells.count == 0
|
22
|
-
puts "\nThey have all perished! D-:"
|
23
|
-
break
|
24
|
-
end
|
25
|
-
|
26
|
-
grid = ""
|
27
|
-
(1..max_y).each do |y|
|
28
|
-
(1..max_x).each do |x|
|
29
|
-
cell_char = cell_content_for(live_cells, x,y)
|
30
|
-
grid << "|#{cell_char}"
|
31
|
-
end
|
32
|
-
grid << "|\n"
|
33
|
-
end
|
34
|
-
|
35
|
-
grid << "\n"
|
36
|
-
|
37
|
-
grid << "Total objects: #{live_object_count} "
|
38
|
-
grid << "Total living cells: #{live_cells.count}\n"
|
39
|
-
|
40
|
-
elapsed_minutes, elapsed_seconds = ((Time.now - start).to_i).divmod 60
|
41
|
-
grid << "Elapsed time: #{elapsed_minutes} min, #{elapsed_seconds} secs\n"
|
42
|
-
|
43
|
-
yield grid if block_given?
|
44
|
-
|
45
|
-
sleep(loop_interval)
|
46
|
-
end while(generation = generation.next)
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
attr_accessor :max_x, :max_y, :starting_cells, :loop_interval
|
51
|
-
|
52
|
-
def cell_content_for(points, x,y)
|
53
|
-
@comparison_point ||= Point.new(x,y)
|
54
|
-
@comparison_point.update(x,y)
|
55
|
-
points.detect {|p| p == @comparison_point } ? "X" : " "
|
56
|
-
end
|
57
|
-
|
58
|
-
def live_object_count
|
59
|
-
if ObjectSpace.respond_to?(:count_objects)
|
60
|
-
# Ruby 1.9.2
|
61
|
-
ObjectSpace.count_objects[:TOTAL]
|
62
|
-
else
|
63
|
-
# Ruby 1.8.7
|
64
|
-
ObjectSpace.live_objects
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|