life 0.1.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/.gitignore +17 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +19 -0
- data/Rakefile +2 -0
- data/lib/life.rb +8 -0
- data/lib/life/cell.rb +22 -0
- data/lib/life/grid.rb +44 -0
- data/lib/life/version.rb +3 -0
- data/lib/life/world.rb +28 -0
- data/life.gemspec +19 -0
- data/spec/life/cell_spec.rb +53 -0
- data/spec/life/grid_spec.rb +52 -0
- data/spec/life/world_spec.rb +80 -0
- data/spec/spec_helper.rb +3 -0
- metadata +81 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Joel Quenneville
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# Life
|
2
|
+
|
3
|
+
A ruby implementation of Conway's [game of life](http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life).
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
$ gem install life
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
TODO: Write usage instructions here
|
12
|
+
|
13
|
+
## Contributing
|
14
|
+
|
15
|
+
1. Fork it
|
16
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
17
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
18
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
19
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/lib/life.rb
ADDED
data/lib/life/cell.rb
ADDED
data/lib/life/grid.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
class Grid < Array
|
2
|
+
|
3
|
+
def initialize(x, y, seed=[])
|
4
|
+
@width = x
|
5
|
+
@height = y
|
6
|
+
super(x) { Array.new(y) { Cell.new(false) } }
|
7
|
+
seed(seed)
|
8
|
+
end
|
9
|
+
|
10
|
+
def deep_copy
|
11
|
+
Marshal.load(Marshal.dump(self))
|
12
|
+
end
|
13
|
+
|
14
|
+
def live_neighbor_count_for(x, y)
|
15
|
+
count = 0
|
16
|
+
x_range(x).each do |curr_x|
|
17
|
+
y_range(y).each do |curr_y|
|
18
|
+
unless (curr_x == x && curr_y == y)
|
19
|
+
count += 1 if self[curr_x][curr_y].live?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
count
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def x_range(x)
|
28
|
+
west = x - 1 < 0 ? 0 : x - 1
|
29
|
+
east = x + 1 > @width - 1 ? @width - 1 : x + 1
|
30
|
+
west..east
|
31
|
+
end
|
32
|
+
|
33
|
+
def y_range(y)
|
34
|
+
north = y - 1 < 0 ? 0 : y - 1
|
35
|
+
south = y + 1 > @height - 1 ? @height - 1 : y + 1
|
36
|
+
north..south
|
37
|
+
end
|
38
|
+
|
39
|
+
def seed(pattern)
|
40
|
+
pattern.each do |x, y|
|
41
|
+
self[x][y].live
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/life/version.rb
ADDED
data/lib/life/world.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
class World
|
2
|
+
|
3
|
+
attr_reader :current
|
4
|
+
|
5
|
+
def initialize(x, y, seed = [])
|
6
|
+
@current = Grid.new(x, y, seed)
|
7
|
+
@next = @current.deep_copy
|
8
|
+
end
|
9
|
+
|
10
|
+
def tick
|
11
|
+
current.each do |row|
|
12
|
+
x = current.index(row)
|
13
|
+
row.each do |cell|
|
14
|
+
y = row.index(cell)
|
15
|
+
if cell.live?
|
16
|
+
case @current.live_neighbor_count_for(x,y)
|
17
|
+
when 0..1 then @next[x][y].kill
|
18
|
+
when 2..3 then @next[x][y].live
|
19
|
+
when 4..8 then @next[x][y].kill
|
20
|
+
end
|
21
|
+
elsif cell.dead? && @current.live_neighbor_count_for(x,y) == 3
|
22
|
+
@next[x][y].live
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
@current = @next.deep_copy
|
27
|
+
end
|
28
|
+
end
|
data/life.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/life/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Joel Quenneville"]
|
6
|
+
gem.email = ["joel.quenneville@collegeplus.org"]
|
7
|
+
gem.description = %q{Conway's Game of life in ruby}
|
8
|
+
gem.summary = %q{Conway's Game of life in ruby}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "life"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Life::VERSION
|
17
|
+
|
18
|
+
gem.add_development_dependency 'rspec'
|
19
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cell do
|
4
|
+
describe "#live?" do
|
5
|
+
subject { cell }
|
6
|
+
context "when live" do
|
7
|
+
let(:cell) { Cell.new(true) }
|
8
|
+
it { should be_live }
|
9
|
+
end
|
10
|
+
context "when dead" do
|
11
|
+
let(:cell) { Cell.new(false) }
|
12
|
+
it { should_not be_live }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#dead?" do
|
17
|
+
subject { cell }
|
18
|
+
context "when live" do
|
19
|
+
let(:cell) { Cell.new(true) }
|
20
|
+
it { should_not be_dead }
|
21
|
+
end
|
22
|
+
context "when dead" do
|
23
|
+
let(:cell) { Cell.new(false) }
|
24
|
+
it { should be_dead }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#live" do
|
29
|
+
subject { cell }
|
30
|
+
before { subject.live }
|
31
|
+
context "when live" do
|
32
|
+
let(:cell) { Cell.new(true) }
|
33
|
+
it { should be_live }
|
34
|
+
end
|
35
|
+
context "when dead" do
|
36
|
+
let(:cell) { Cell.new(false) }
|
37
|
+
it { should be_live }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#kill" do
|
42
|
+
subject { cell }
|
43
|
+
before { subject.kill }
|
44
|
+
context "when live" do
|
45
|
+
let(:cell) { Cell.new(true) }
|
46
|
+
it { should_not be_live }
|
47
|
+
end
|
48
|
+
context "when dead" do
|
49
|
+
let(:cell) { Cell.new(false) }
|
50
|
+
it { should_not be_live }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Grid do
|
4
|
+
|
5
|
+
describe ".new" do
|
6
|
+
let(:grid) { Grid.new(10, 8) }
|
7
|
+
it "should be a 2d array that is 10 wide" do
|
8
|
+
grid.length.should eq 10
|
9
|
+
end
|
10
|
+
it "should be a 2d array that is 8 high" do
|
11
|
+
grid.first.length.should eq 8
|
12
|
+
end
|
13
|
+
it "should be populated with dead cells" do
|
14
|
+
grid[0][1].live?.should be_false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#deep_copy" do
|
19
|
+
let(:grid) { Grid.new(3,4) }
|
20
|
+
it "should create a distinct copy" do
|
21
|
+
grid.deep_copy.should_not eq grid
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "seed pattern" do
|
26
|
+
let(:grid) { Grid.new(4,5, [[0,0], [1,2], [3,1]])}
|
27
|
+
it "should be initialized correctly" do
|
28
|
+
grid[0][0].should be_live
|
29
|
+
grid[1][2].should be_live
|
30
|
+
grid[3][1].should be_live
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#live_neighbor_count_for" do
|
35
|
+
let(:grid) { Grid.new(3,3, [[1,0], [0,1], [2,1], [1,2]])}
|
36
|
+
context "when NW corner" do
|
37
|
+
it "should return the right amount" do
|
38
|
+
grid.live_neighbor_count_for(0,0).should eq 2
|
39
|
+
end
|
40
|
+
end
|
41
|
+
context "when SE corner" do
|
42
|
+
it "should return the right amount" do
|
43
|
+
grid.live_neighbor_count_for(2,2).should eq 2
|
44
|
+
end
|
45
|
+
end
|
46
|
+
context "when center" do
|
47
|
+
it "should return the right amount" do
|
48
|
+
grid.live_neighbor_count_for(1,1).should eq 4
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe World do
|
4
|
+
describe "blank world" do
|
5
|
+
let(:world) { World.new(10, 8) }
|
6
|
+
it "should be populated by separate cells" do
|
7
|
+
world.current[0][1].should_not eq world.current[1][1]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "seed pattern" do
|
12
|
+
let(:world) { World.new(4,5, [[0,0], [1,2], [3,1]])}
|
13
|
+
it "should be initialized correctly" do
|
14
|
+
world.current[0][0].should be_live
|
15
|
+
world.current[1][2].should be_live
|
16
|
+
world.current[3][1].should be_live
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "Rules" do
|
21
|
+
before { world.tick }
|
22
|
+
subject { world.current[1][1] }
|
23
|
+
|
24
|
+
describe "Any live cell with fewer than two live neighbours dies, as if caused by under-population" do
|
25
|
+
context "when 0 neighbours" do
|
26
|
+
let(:world) { World.new(3,3, [[1,1]]) }
|
27
|
+
it { should be_dead }
|
28
|
+
end
|
29
|
+
context "when 1 neighbours" do
|
30
|
+
let(:world) { World.new(3,3, [[1,1], [0,0]]) }
|
31
|
+
it { should be_dead }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "Any live cell with two or three live neighbours lives on to the next generation." do
|
36
|
+
context "when 2 neighbours" do
|
37
|
+
let(:world) { World.new(3,3, [[1,1], [0,0], [0,1]]) }
|
38
|
+
it { should be_live }
|
39
|
+
end
|
40
|
+
|
41
|
+
context "when 3 neighbours" do
|
42
|
+
let(:world) { World.new(3,3, [[1,1], [0,0], [0,1], [0,2]]) }
|
43
|
+
it { should be_live }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "Any live cell with more than three live neighbours dies, as if by overcrowding." do
|
48
|
+
context "when 4 neighbours" do
|
49
|
+
let(:world) { World.new(3,3, [[1,1], [0,0], [0,1], [0,2], [1,0]]) }
|
50
|
+
it { should be_dead }
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when 5 neighbours" do
|
54
|
+
let(:world) { World.new(3,3, [[1,1], [0,0], [0,1], [0,2], [1,0], [1,2]]) }
|
55
|
+
it { should be_dead }
|
56
|
+
end
|
57
|
+
|
58
|
+
context "when 6 neighbours" do
|
59
|
+
let(:world) { World.new(3,3, [[1,1], [0,0], [0,1], [0,2], [1,0], [1,2], [2,0]]) }
|
60
|
+
it { should be_dead }
|
61
|
+
end
|
62
|
+
|
63
|
+
context "when 7 neighbours" do
|
64
|
+
let(:world) { World.new(3,3, [[1,1], [0,0], [0,1], [0,2], [1,0], [1,2], [2,0], [2,1]]) }
|
65
|
+
it { should be_dead }
|
66
|
+
end
|
67
|
+
|
68
|
+
context "when 8 neighbours" do
|
69
|
+
let(:world) { World.new(3,3, [[1,1], [0,0], [0,1], [0,2], [1,0], [1,2], [2,0], [2,1], [2,2]]) }
|
70
|
+
it { should be_dead }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction." do
|
75
|
+
let(:world) { World.new(3,3, [[0,0], [0,1], [0,2]]) }
|
76
|
+
it { should be_live }
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: life
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Joel Quenneville
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-09-18 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
description: Conway's Game of life in ruby
|
31
|
+
email:
|
32
|
+
- joel.quenneville@collegeplus.org
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- .gitignore
|
38
|
+
- .rspec
|
39
|
+
- Gemfile
|
40
|
+
- LICENSE
|
41
|
+
- README.md
|
42
|
+
- Rakefile
|
43
|
+
- lib/life.rb
|
44
|
+
- lib/life/cell.rb
|
45
|
+
- lib/life/grid.rb
|
46
|
+
- lib/life/version.rb
|
47
|
+
- lib/life/world.rb
|
48
|
+
- life.gemspec
|
49
|
+
- spec/life/cell_spec.rb
|
50
|
+
- spec/life/grid_spec.rb
|
51
|
+
- spec/life/world_spec.rb
|
52
|
+
- spec/spec_helper.rb
|
53
|
+
homepage: ''
|
54
|
+
licenses: []
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options: []
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ! '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
requirements: []
|
72
|
+
rubyforge_project:
|
73
|
+
rubygems_version: 1.8.21
|
74
|
+
signing_key:
|
75
|
+
specification_version: 3
|
76
|
+
summary: Conway's Game of life in ruby
|
77
|
+
test_files:
|
78
|
+
- spec/life/cell_spec.rb
|
79
|
+
- spec/life/grid_spec.rb
|
80
|
+
- spec/life/world_spec.rb
|
81
|
+
- spec/spec_helper.rb
|