ruby_life 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 716e87982dcd1319e6da966a7c471b9522c26003
4
+ data.tar.gz: b0bcbff0820634af5cbc22a3f809715ce65d13fc
5
+ SHA512:
6
+ metadata.gz: b4214dbeb9d7170b5f793fbe1ff26d22335976a0652ae63e052933f46f787d31a09fcb6d792e99ff9011e83a3713f94710724a42664b6b41b3ee3ad2daecc1d0
7
+ data.tar.gz: 13df4d2f782c0ef107b7933de3645cab0df4a4b59270fef9fbff580e5363f313382307428b67cbf61afdb434fba9a3490a61ba7f3dd2bc739442ee7c10f87c67
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ game-of-life
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,27 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ ruby_life (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.2.4)
10
+ rake (10.1.0)
11
+ rspec (2.14.1)
12
+ rspec-core (~> 2.14.0)
13
+ rspec-expectations (~> 2.14.0)
14
+ rspec-mocks (~> 2.14.0)
15
+ rspec-core (2.14.7)
16
+ rspec-expectations (2.14.3)
17
+ diff-lcs (>= 1.1.3, < 2.0)
18
+ rspec-mocks (2.14.4)
19
+
20
+ PLATFORMS
21
+ ruby
22
+
23
+ DEPENDENCIES
24
+ bundler (~> 1.3)
25
+ rake
26
+ rspec
27
+ ruby_life!
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Eno Compton 4
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,20 @@
1
+ Ruby Life
2
+ =========
3
+
4
+ A test-driven implementation of Conway's Game of Life in Ruby.
5
+
6
+ The Rules
7
+ =========
8
+
9
+ 1. Any live cell with fewer than two live neighbours dies,
10
+ as if caused by under-population.
11
+
12
+ 2. Any live cell with two or three live neighbours
13
+ lives on to the next generation.
14
+
15
+ 3. Any live cell with more than three live
16
+ neighbours dies, as if by overcrowding
17
+
18
+ 4. Any dead cell with exactly three live neighbours
19
+ becomes a live cell, as if by reproduction.
20
+
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
7
+
data/bin/ruby_life ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ruby_life'
4
+ RubyLife::Game.new.run
5
+
@@ -0,0 +1,30 @@
1
+ module RubyLife
2
+ class Cell
3
+ attr_reader :status
4
+
5
+ def initialize(status = nil)
6
+ @status = status || [:alive, :dead].sample
7
+ end
8
+
9
+ def alive?
10
+ @status == :alive
11
+ end
12
+
13
+ def dead?
14
+ @status == :dead
15
+ end
16
+
17
+ def die!
18
+ @status = :dead
19
+ end
20
+
21
+ def live!
22
+ @status = :alive
23
+ end
24
+
25
+ def to_s
26
+ alive? ? "o" : "."
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,4 @@
1
+ module RubyLife
2
+ class BadInitialState < StandardError; end
3
+ end
4
+
@@ -0,0 +1,31 @@
1
+ module RubyLife
2
+ class Game
3
+ def initialize
4
+ @grid = Grid.new(40)
5
+ end
6
+
7
+ def run
8
+ clear_screen
9
+
10
+ i = 0
11
+ loop do
12
+ puts "generation #{i}"
13
+ puts @grid
14
+ @grid.generate!
15
+ animate_transition
16
+ i += 1
17
+ end
18
+ end
19
+
20
+ private
21
+ def clear_screen
22
+ print "\e[H\e[2J"
23
+ end
24
+
25
+ def animate_transition
26
+ sleep 1
27
+ clear_screen
28
+ end
29
+ end
30
+ end
31
+
@@ -0,0 +1,112 @@
1
+ module RubyLife
2
+ class Grid
3
+ attr_reader :size
4
+
5
+ def initialize(size, state: nil)
6
+ @size = size
7
+ if state
8
+ raise BadInitialState unless size_matches_state?(@size, state)
9
+
10
+ @storage = state.map { |status| Cell.new(status) }
11
+ else
12
+ @storage = number_of_cells(@size).times.map { Cell.new }
13
+ end
14
+ end
15
+
16
+ def get_neighbors_from_index(index)
17
+ indices_to_retrieve = []
18
+ indices_to_retrieve << (index - 1) unless beginning_of_row?(index)
19
+ indices_to_retrieve << (index + 1) unless end_of_row?(index)
20
+
21
+ unless first_row?(index)
22
+ indices_to_retrieve << (above(index - 1)) unless beginning_of_row?(index)
23
+ indices_to_retrieve << (above(index + 1)) unless end_of_row?(index)
24
+ indices_to_retrieve << (above(index))
25
+ end
26
+
27
+ unless last_row?(index)
28
+ indices_to_retrieve << (below(index) - 1) unless beginning_of_row?(index)
29
+ indices_to_retrieve << (below(index) + 1) unless end_of_row?(index)
30
+ indices_to_retrieve << (below(index))
31
+ end
32
+
33
+ indices_to_retrieve.map { |i| @storage[i] }
34
+ end
35
+
36
+ def [](x, y)
37
+ @storage[x + (y * size)]
38
+ end
39
+
40
+ def generate!
41
+ next_generation = {}
42
+
43
+ @storage.each_with_index do |cell, index|
44
+ neighbors = get_neighbors_from_index(index)
45
+ living_neighbor_count = neighbors.select(&:alive?).count
46
+
47
+ if cell.alive? && [2, 3].include?(living_neighbor_count)
48
+ next_generation[index] = :alive
49
+ elsif cell.alive? && living_neighbor_count == 4
50
+ next_generation[index] = :dead
51
+ elsif cell.dead? && living_neighbor_count == 3
52
+ next_generation[index] = :alive
53
+ else
54
+ next_generation[index] = :dead
55
+ end
56
+ end
57
+
58
+ next_generation.each do |index, status|
59
+ status == :alive ? @storage[index].live! : @storage[index].die!
60
+ end
61
+ end
62
+
63
+ def state
64
+ @storage.map(&:status)
65
+ end
66
+
67
+ def to_s
68
+ grid_string = ""
69
+
70
+ @storage.each_with_index do |cell, index|
71
+ grid_string += " #{cell}"
72
+ grid_string += "\n" if end_of_row?(index)
73
+ end
74
+
75
+ grid_string
76
+ end
77
+
78
+ private
79
+ def beginning_of_row?(index)
80
+ index % size == 0
81
+ end
82
+
83
+ def end_of_row?(index)
84
+ (index + 1) % size == 0
85
+ end
86
+
87
+ def first_row?(index)
88
+ index < size
89
+ end
90
+
91
+ def last_row?(index)
92
+ index >= (number_of_cells(size) - size)
93
+ end
94
+
95
+ def size_matches_state?(size, state)
96
+ number_of_cells(size) == state.length
97
+ end
98
+
99
+ def above(index)
100
+ index - size
101
+ end
102
+
103
+ def below(index)
104
+ index + size
105
+ end
106
+
107
+ def number_of_cells(size)
108
+ size * size
109
+ end
110
+ end
111
+ end
112
+
@@ -0,0 +1,3 @@
1
+ module RubyLife
2
+ VERSION = "0.0.1"
3
+ end
data/lib/ruby_life.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'ruby_life/cell'
2
+ require 'ruby_life/exceptions'
3
+ require 'ruby_life/game'
4
+ require 'ruby_life/grid'
5
+ require 'ruby_life/version'
6
+
7
+ module RubyLife
8
+ end
9
+
data/ruby_life.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ruby_life/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "ruby_life"
8
+ gem.version = RubyLife::VERSION
9
+ gem.authors = ["Eno Compton 4"]
10
+ gem.email = ["eno4@ecom.com"]
11
+ gem.description = %q{A command line version of Conway's Game of Life}
12
+ gem.summary = %q{Observe cells as they live and die on the CLI.}
13
+ gem.homepage = "http://github.com/enocom/ruby_life"
14
+ gem.license = "MIT"
15
+
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ["lib"]
20
+
21
+ gem.add_development_dependency "bundler", "~> 1.3"
22
+ gem.add_development_dependency "rake"
23
+ gem.add_development_dependency "rspec"
24
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe RubyLife::Cell do
4
+ let(:cell) { RubyLife::Cell.new }
5
+
6
+ it 'can live and die' do
7
+ cell.live!
8
+ expect(cell.alive?).to be_true
9
+ cell.die!
10
+ expect(cell.alive?).to be_false
11
+ end
12
+
13
+ it 'takes an optional status' do
14
+ dead_cell = RubyLife::Cell.new(:dead)
15
+ expect(dead_cell.alive?).to be_false
16
+ end
17
+ end
18
+
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe RubyLife::Game do
4
+ end
5
+
@@ -0,0 +1,174 @@
1
+ require 'spec_helper'
2
+
3
+ describe RubyLife::Grid do
4
+ let(:grid) { RubyLife::Grid.new(3) }
5
+
6
+ it 'accepts a dimension as an argument' do
7
+ expect(grid.state.length).to eq 9
8
+ end
9
+
10
+ it 'initializes separate instances of cells' do
11
+ expect(grid[0, 0].object_id).not_to eq(grid[0, 1].object_id)
12
+ end
13
+
14
+ it 'can retrieve cells from the grid' do
15
+ grid = RubyLife::Grid.new(3, state: [:dead, :dead, :dead,
16
+ :dead, :alive, :dead,
17
+ :dead, :dead, :dead])
18
+ expect(grid[1,1].alive?).to be_true
19
+
20
+ grid = RubyLife::Grid.new(3, state: [:dead, :alive, :dead,
21
+ :dead, :dead, :dead,
22
+ :dead, :dead, :dead])
23
+ expect(grid[1,0].alive?).to be_true
24
+
25
+ grid = RubyLife::Grid.new(3, state: [:dead, :dead, :dead,
26
+ :dead, :dead, :dead,
27
+ :dead, :alive, :dead])
28
+ expect(grid[1,2].alive?).to be_true
29
+ end
30
+
31
+ context 'specifying an initial state' do
32
+ it 'accepts an initial state' do
33
+ grid = RubyLife::Grid.new(2, state: [:dead, :alive, :dead, :alive])
34
+ expect(grid[0, 0].alive?).to be_false
35
+ expect(grid[1, 1].alive?).to be_true
36
+ end
37
+
38
+ it 'raises an error when passed mismatching dimensions and state' do
39
+ expect {
40
+ RubyLife::Grid.new(2, state: [:dead])
41
+ }.to raise_error(RubyLife::BadInitialState)
42
+
43
+ expect {
44
+ RubyLife::Grid.new(2, state: [:dead, :alive, :dead])
45
+ }.to raise_error(RubyLife::BadInitialState)
46
+ end
47
+ end
48
+
49
+ context 'retrieving neighboring cells' do
50
+ it 'finds neighbors of cells away from edges' do
51
+ expect(grid.get_neighbors_from_index(4).size).to eq 8
52
+ end
53
+
54
+ it 'finds neighbors of the corner cells' do
55
+ expect(grid.get_neighbors_from_index(0).size).to eq 3
56
+ expect(grid.get_neighbors_from_index(2).size).to eq 3
57
+ expect(grid.get_neighbors_from_index(6).size).to eq 3
58
+ expect(grid.get_neighbors_from_index(8).size).to eq 3
59
+ end
60
+
61
+ it 'finds neighbors of the edge cells' do
62
+ expect(grid.get_neighbors_from_index(1).size).to eq 5
63
+ expect(grid.get_neighbors_from_index(3).size).to eq 5
64
+ expect(grid.get_neighbors_from_index(5).size).to eq 5
65
+ expect(grid.get_neighbors_from_index(7).size).to eq 5
66
+ end
67
+ end
68
+
69
+ context 'printing the grid' do
70
+ it 'renders the live and dead cells' do
71
+ grid = RubyLife::Grid.new(2, state: [:dead, :alive, :alive, :dead])
72
+ expected_grid =" . o\n o .\n"
73
+ expect(grid.to_s).to eq expected_grid
74
+ end
75
+ end
76
+
77
+ context 'rule 1: any live cell with fewer than two live neighbors dies' do
78
+ specify 'a sole survivor dies' do
79
+ grid = RubyLife::Grid.new(2, state: [:dead, :dead,
80
+ :dead, :alive])
81
+ grid.generate!
82
+
83
+ expect(grid.state).to eq [:dead, :dead,
84
+ :dead, :dead]
85
+ end
86
+
87
+ specify 'two sole survivors die' do
88
+ grid = RubyLife::Grid.new(2, state: [:dead, :dead,
89
+ :alive, :alive])
90
+ grid.generate!
91
+
92
+ expect(grid.state).to eq [:dead, :dead,
93
+ :dead, :dead]
94
+ end
95
+ end
96
+
97
+ context 'rule 2: any live cell with two or three live neighbors lives' do
98
+ specify 'any live cell with two live neighbors lives' do
99
+ grid = RubyLife::Grid.new(2, state: [:dead, :alive,
100
+ :alive, :alive])
101
+ grid.generate!
102
+
103
+ expect(grid.state).to eq [:alive, :alive,
104
+ :alive, :alive]
105
+ end
106
+
107
+ specify 'any live cell with three live neighbors lives' do
108
+ grid = RubyLife::Grid.new(2, state: [:alive, :alive,
109
+ :alive, :alive])
110
+ grid.generate!
111
+
112
+ expect(grid.state).to eq [:alive, :alive,
113
+ :alive, :alive]
114
+ end
115
+ end
116
+
117
+ context 'rule 3: a live cell dies with more than three live neighbors' do
118
+ specify 'a cell dies with four live neighbors' do
119
+ grid = RubyLife::Grid.new(3, state: [:alive, :alive, :dead,
120
+ :alive, :alive, :alive,
121
+ :dead, :dead, :dead])
122
+ grid.generate!
123
+
124
+ expect(grid.state).to eq [:alive, :dead, :alive,
125
+ :alive, :dead, :alive,
126
+ :dead, :alive, :dead]
127
+ end
128
+ end
129
+
130
+ context 'rule 4: a dead cell with extactly three live neighbors lives' do
131
+ specify 'a dead cell lives with three live neighbors' do
132
+ grid = RubyLife::Grid.new(2, state: [:dead, :alive,
133
+ :alive, :alive])
134
+
135
+ grid.generate!
136
+
137
+ expect(grid.state).to eq [:alive, :alive,
138
+ :alive, :alive]
139
+ end
140
+ end
141
+
142
+ context 'big grids' do
143
+ specify 'big grids respect all four rules' do
144
+ big_grid = RubyLife::Grid.new(5, state: [
145
+ :alive, :alive, :alive, :alive, :alive,
146
+ :alive, :alive, :alive, :alive, :alive,
147
+ :alive, :alive, :alive, :alive, :alive,
148
+ :alive, :alive, :alive, :alive, :alive,
149
+ :alive, :alive, :alive, :alive, :alive
150
+ ])
151
+
152
+ big_grid.generate!
153
+
154
+ expect(big_grid.state).to eq [
155
+ :alive, :dead, :dead, :dead, :alive,
156
+ :dead, :dead, :dead, :dead, :dead,
157
+ :dead, :dead, :dead, :dead, :dead,
158
+ :dead, :dead, :dead, :dead, :dead,
159
+ :alive, :dead, :dead, :dead, :alive
160
+ ]
161
+
162
+ big_grid.generate!
163
+
164
+ expect(big_grid.state).to eq [
165
+ :dead, :dead, :dead, :dead, :dead,
166
+ :dead, :dead, :dead, :dead, :dead,
167
+ :dead, :dead, :dead, :dead, :dead,
168
+ :dead, :dead, :dead, :dead, :dead,
169
+ :dead, :dead, :dead, :dead, :dead
170
+ ]
171
+ end
172
+ end
173
+ end
174
+
@@ -0,0 +1,6 @@
1
+ require 'rspec'
2
+ require 'ruby_life'
3
+
4
+ Dir[File.join(File.dirname(__FILE__), "../lib/ruby_life.rb")]
5
+ .each { |f| require f }
6
+
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby_life
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Eno Compton 4
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: A command line version of Conway's Game of Life
56
+ email:
57
+ - eno4@ecom.com
58
+ executables:
59
+ - ruby_life
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - .gitignore
64
+ - .rspec
65
+ - .ruby-gemset
66
+ - .ruby-version
67
+ - Gemfile
68
+ - Gemfile.lock
69
+ - LICENSE.txt
70
+ - README.md
71
+ - Rakefile
72
+ - bin/ruby_life
73
+ - lib/ruby_life.rb
74
+ - lib/ruby_life/cell.rb
75
+ - lib/ruby_life/exceptions.rb
76
+ - lib/ruby_life/game.rb
77
+ - lib/ruby_life/grid.rb
78
+ - lib/ruby_life/version.rb
79
+ - ruby_life.gemspec
80
+ - spec/ruby_life/cell_spec.rb
81
+ - spec/ruby_life/game_spec.rb
82
+ - spec/ruby_life/grid_spec.rb
83
+ - spec/spec_helper.rb
84
+ homepage: http://github.com/enocom/ruby_life
85
+ licenses:
86
+ - MIT
87
+ metadata: {}
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubyforge_project:
104
+ rubygems_version: 2.0.6
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: Observe cells as they live and die on the CLI.
108
+ test_files:
109
+ - spec/ruby_life/cell_spec.rb
110
+ - spec/ruby_life/game_spec.rb
111
+ - spec/ruby_life/grid_spec.rb
112
+ - spec/spec_helper.rb