game-of-life 0.1.1
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.
- checksums.yaml +15 -0
- data/.ruby-version +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +18 -0
- data/Rakefile +10 -0
- data/bin/game-of-life +8 -0
- data/game-of-life.gemspec +24 -0
- data/lib/game-of-life/cell.rb +33 -0
- data/lib/game-of-life/exceptions.rb +2 -0
- data/lib/game-of-life/version.rb +6 -0
- data/lib/game-of-life/world.rb +316 -0
- data/lib/game_of_life.rb +60 -0
- data/test/lib/game-of-life/cell_test.rb +62 -0
- data/test/lib/game-of-life/world_test.rb +85 -0
- data/test/rules/first_rule_test.rb +35 -0
- data/test/rules/fourth_rule_test.rb +24 -0
- data/test/rules/second_rule_test.rb +33 -0
- data/test/rules/third_rule_test.rb +26 -0
- data/test/test_helper.rb +2 -0
- metadata +98 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NTdhOTY3OTFmZWFjZTdhM2IwNzc5MzliMTY4NTBkOWFiM2IxMGE1Nw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZTc2ZDBlNjM5OTBlOGJjYzczMjYyYTZjM2U3ZDJiY2RiMjNiY2NkMw==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZmU2NDQ4YzU1OGEyYzY4YmEwNzI3MTU4YjliZjAyMjFlNWU4NGEwMzc1MzYz
|
10
|
+
YzRjNzhiZTY3YzEzYzI5OWE2OGY5OTUxNTU3MWY2M2JlZDM1YWQ0MDdmMzI3
|
11
|
+
MDBjYzAzMzE5OTdiMjc5OWI5MjZjNmZiZWY0ODk0MjQ3MjBkYzM=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NDc3YTQxNjE2ZWFmZDk1ZjdhNjA3YjhmNjMxMmIxNTc5MGVmNGY1YzkwZWUw
|
14
|
+
NzY0ZDBlMjE4MzRmN2UzZDY3YTUwY2RmZDU4MzU3NDcyYTdkNzQ3Y2EwNWI0
|
15
|
+
MjI4MjVlOGFmMjBhOTI3ZGEzMTY2NWRlYTQ0YWYzNjgzNzk3Zjg=
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-1.9.3-p448
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/Rakefile
ADDED
data/bin/game-of-life
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'game-of-life/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "game-of-life"
|
8
|
+
gem.version = GameOfLife::VERSION
|
9
|
+
gem.authors = ["Thiago Rocha"]
|
10
|
+
gem.email = ["kimo@kimo.io"]
|
11
|
+
gem.description = %q{The Game of Life}
|
12
|
+
gem.summary = %q{A gem that shows random matches of Conway's Game of Life }
|
13
|
+
gem.homepage = "http://thiagokimo.github.io/game-of-life"
|
14
|
+
|
15
|
+
gem.license = 'MIT'
|
16
|
+
|
17
|
+
gem.files = `git ls-files`.split($/)
|
18
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
19
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
20
|
+
gem.require_paths = ["lib"]
|
21
|
+
gem.add_development_dependency 'rake'
|
22
|
+
|
23
|
+
gem.add_dependency 'gosu'
|
24
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module GameOfLife
|
2
|
+
class Cell
|
3
|
+
attr_accessor :x, :y, :alive, :neighbours
|
4
|
+
def initialize(x=0,y=0,alive=true)
|
5
|
+
@x,@y = x,y
|
6
|
+
@alive = alive
|
7
|
+
end
|
8
|
+
|
9
|
+
def ==(otherCell)
|
10
|
+
(self.x == otherCell.x) and (self.y == otherCell.y)
|
11
|
+
end
|
12
|
+
|
13
|
+
def neighbours
|
14
|
+
[]
|
15
|
+
end
|
16
|
+
|
17
|
+
def alive?
|
18
|
+
self.alive
|
19
|
+
end
|
20
|
+
|
21
|
+
def dead?
|
22
|
+
not alive?
|
23
|
+
end
|
24
|
+
|
25
|
+
def reborn!
|
26
|
+
@alive = true
|
27
|
+
end
|
28
|
+
|
29
|
+
def die!
|
30
|
+
@alive = false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,316 @@
|
|
1
|
+
require 'matrix'
|
2
|
+
|
3
|
+
module GameOfLife
|
4
|
+
class World
|
5
|
+
attr_accessor :cells, :board
|
6
|
+
|
7
|
+
def initialize(width,height)
|
8
|
+
@width, @height = width, height
|
9
|
+
setup(false)
|
10
|
+
end
|
11
|
+
|
12
|
+
def seed!
|
13
|
+
clean_cells
|
14
|
+
setup(true)
|
15
|
+
end
|
16
|
+
|
17
|
+
def live_cells
|
18
|
+
@cells.select { |cell| cell.alive? }
|
19
|
+
end
|
20
|
+
|
21
|
+
def dead_cells
|
22
|
+
@cells.select { |cell| cell.dead? }
|
23
|
+
end
|
24
|
+
|
25
|
+
def kill(x,y)
|
26
|
+
@board.element(x,y).die!
|
27
|
+
end
|
28
|
+
|
29
|
+
def get(x,y)
|
30
|
+
@board.element(x,y)
|
31
|
+
end
|
32
|
+
|
33
|
+
def revive(x,y)
|
34
|
+
@board.element(x,y).reborn!
|
35
|
+
end
|
36
|
+
|
37
|
+
def live_neighbours_of(x,y)
|
38
|
+
live_neighbours = []
|
39
|
+
|
40
|
+
# up-left
|
41
|
+
if x-1 >= 0 and y+1 <= @height-1
|
42
|
+
neighbour = get(x-1,y+1)
|
43
|
+
live_neighbours << neighbour if neighbour.alive?
|
44
|
+
end
|
45
|
+
|
46
|
+
# up
|
47
|
+
if y+1 <= @height-1
|
48
|
+
neighbour = get(x,y+1)
|
49
|
+
live_neighbours << neighbour if neighbour.alive?
|
50
|
+
end
|
51
|
+
|
52
|
+
# up-right
|
53
|
+
if x+1 <= @width-1 and y+1 <= @height-1
|
54
|
+
neighbour = get(x+1,y+1)
|
55
|
+
live_neighbours << neighbour if neighbour.alive?
|
56
|
+
end
|
57
|
+
|
58
|
+
# left
|
59
|
+
if x-1 >= 0
|
60
|
+
neighbour = get(x-1,y)
|
61
|
+
live_neighbours << neighbour if neighbour.alive?
|
62
|
+
end
|
63
|
+
|
64
|
+
# right
|
65
|
+
if x+1 <= @width-1
|
66
|
+
neighbour = get(x+1,y)
|
67
|
+
live_neighbours << neighbour if neighbour.alive?
|
68
|
+
end
|
69
|
+
|
70
|
+
# down-left
|
71
|
+
if x-1 >= 0 and y-1 >= 0
|
72
|
+
neighbour = get(x-1,y-1)
|
73
|
+
live_neighbours << neighbour if neighbour.alive?
|
74
|
+
end
|
75
|
+
|
76
|
+
# down
|
77
|
+
if y-1 >= 0
|
78
|
+
neighbour = get(x,y-1)
|
79
|
+
live_neighbours << neighbour if neighbour.alive?
|
80
|
+
end
|
81
|
+
|
82
|
+
# down-right
|
83
|
+
if x+1 <= @width-1 and y-1 >= 0
|
84
|
+
neighbour = get(x+1,y-1)
|
85
|
+
live_neighbours << neighbour if neighbour.alive?
|
86
|
+
end
|
87
|
+
|
88
|
+
live_neighbours
|
89
|
+
end
|
90
|
+
|
91
|
+
def rotate!
|
92
|
+
future_alive_cells = []
|
93
|
+
future_dead_cells = []
|
94
|
+
|
95
|
+
@cells.each do |cell|
|
96
|
+
live_neighbours = live_neighbours_of(cell.x,cell.y)
|
97
|
+
|
98
|
+
future_dead_cells << cell if apply_rule_1(cell,live_neighbours)
|
99
|
+
future_alive_cells << cell if apply_rule_2(cell,live_neighbours)
|
100
|
+
future_dead_cells << cell if apply_rule_3(cell,live_neighbours)
|
101
|
+
future_alive_cells << cell if apply_rule_4(cell,live_neighbours)
|
102
|
+
end
|
103
|
+
|
104
|
+
update_board(future_alive_cells,future_dead_cells)
|
105
|
+
update_cells
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
def apply_rule_1(cell,live_neighbours)
|
110
|
+
cell.alive? and live_neighbours.count < 2
|
111
|
+
end
|
112
|
+
|
113
|
+
def apply_rule_2(cell,live_neighbours)
|
114
|
+
cell.alive? and (live_neighbours.count == 2 or live_neighbours.count == 3)
|
115
|
+
end
|
116
|
+
|
117
|
+
def apply_rule_3(cell,live_neighbours)
|
118
|
+
cell.alive? and live_neighbours.count > 3
|
119
|
+
end
|
120
|
+
|
121
|
+
def apply_rule_4(cell,live_neighbours)
|
122
|
+
cell.dead? and live_neighbours.count == 3
|
123
|
+
end
|
124
|
+
|
125
|
+
def rebuild_board(live_cells,dead_cells)
|
126
|
+
(live_cells+dead_cells).each do |cell|
|
127
|
+
@board.set(cell.x,cell.y,cell)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def setup(random)
|
132
|
+
@board = Matrix.build(@width, @height) { |row,column|
|
133
|
+
if random
|
134
|
+
cell = Cell.new(row,column,[true,false].sample)
|
135
|
+
else
|
136
|
+
cell = Cell.new(row,column)
|
137
|
+
end
|
138
|
+
}
|
139
|
+
|
140
|
+
update_cells
|
141
|
+
end
|
142
|
+
|
143
|
+
def update_board(to_live,to_die)
|
144
|
+
to_live.each do |cell|
|
145
|
+
revive(cell.x,cell.y)
|
146
|
+
end
|
147
|
+
to_die.each do |cell|
|
148
|
+
kill(cell.x,cell.y)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def update_cells
|
153
|
+
@cells = @board.to_a.flatten!
|
154
|
+
end
|
155
|
+
|
156
|
+
def clean_cells
|
157
|
+
@cells = nil
|
158
|
+
@board = nil
|
159
|
+
end
|
160
|
+
end
|
161
|
+
# class World
|
162
|
+
# attr_accessor :cells, :board
|
163
|
+
# attr_reader :width, :height
|
164
|
+
|
165
|
+
# def initialize(width=10, height=10, allow_negative_cells=true)
|
166
|
+
# @width, @height = width, height
|
167
|
+
# @negative = allow_negative_cells
|
168
|
+
# @cells = []
|
169
|
+
|
170
|
+
# setup_board
|
171
|
+
# end
|
172
|
+
|
173
|
+
# def dead_cells
|
174
|
+
# @cells.select { |cell| cell.dead? }
|
175
|
+
# end
|
176
|
+
|
177
|
+
# def live_cells
|
178
|
+
# @cells.select { |cell| cell.alive? }
|
179
|
+
# end
|
180
|
+
|
181
|
+
# def seed!
|
182
|
+
# for x in (0).upto(@width-1) do
|
183
|
+
# for y in (0).upto(@height-1) do
|
184
|
+
# cell = Cell.new(x,y,[true,false].sample)
|
185
|
+
# @cells << cell
|
186
|
+
# @board[x][y] = cell
|
187
|
+
# end
|
188
|
+
# end
|
189
|
+
# end
|
190
|
+
|
191
|
+
# # up_left | up | up_right
|
192
|
+
# # ----------|------|-----------
|
193
|
+
# # left | cell | right
|
194
|
+
# # ----------|------|-----------
|
195
|
+
# # down_left | down | down_right
|
196
|
+
# def live_neighbours_of(cell)
|
197
|
+
# live_neighbours = []
|
198
|
+
|
199
|
+
# up_left = Cell.new(cell.x-1,cell.y+1)
|
200
|
+
# up = Cell.new(cell.x,cell.y+1)
|
201
|
+
# up_right = Cell.new(cell.x+1,cell.y+1)
|
202
|
+
# left = Cell.new(cell.x-1,cell.y)
|
203
|
+
# right = Cell.new(cell.x+1,cell.y)
|
204
|
+
# down_left = Cell.new(cell.x-1,cell.y-1)
|
205
|
+
# down = Cell.new(cell.x,cell.y-1)
|
206
|
+
# down_right = Cell.new(cell.x+1,cell.y-1)
|
207
|
+
|
208
|
+
# neighbour_candidates = [up_left,up,up_right,left,right,down_left,down,down_right]
|
209
|
+
|
210
|
+
# neighbour_candidates.each do |neighbour|
|
211
|
+
# live_neighbours << @board[neighbour.x][neighbour.y] if not outside_of_the_world?(neighbour) and neighbour.alive?
|
212
|
+
# end
|
213
|
+
|
214
|
+
# live_neighbours
|
215
|
+
# end
|
216
|
+
|
217
|
+
# def exist?(cell)
|
218
|
+
# @cells.include? cell
|
219
|
+
# end
|
220
|
+
|
221
|
+
# def rotate!
|
222
|
+
# future_alive_cells = []
|
223
|
+
# future_dead_cells = []
|
224
|
+
|
225
|
+
# @cells.each do |cell|
|
226
|
+
# num_live_neighbours = live_neighbours_of(cell).count
|
227
|
+
|
228
|
+
# # Rule #1
|
229
|
+
# if cell.alive? and num_live_neighbours < 2
|
230
|
+
# future_dead_cells << cell
|
231
|
+
# end
|
232
|
+
|
233
|
+
# # Rule #2
|
234
|
+
# if live_neighbours_of(cell).count == 2 or live_neighbours_of(cell).count == 3
|
235
|
+
# future_alive_cells << cell
|
236
|
+
# end
|
237
|
+
|
238
|
+
# # Rule #3
|
239
|
+
# if cell.alive? and num_live_neighbours > 3
|
240
|
+
# future_dead_cells << cell
|
241
|
+
# end
|
242
|
+
|
243
|
+
# # Rule #4
|
244
|
+
# if cell.dead? and num_live_neighbours == 3
|
245
|
+
# future_alive_cells << cell
|
246
|
+
# end
|
247
|
+
|
248
|
+
# update_cells(future_alive_cells,future_dead_cells)
|
249
|
+
# end
|
250
|
+
# end
|
251
|
+
|
252
|
+
# def create(cell)
|
253
|
+
# # raise CellAlreadyExistsInTheWorldException if exist?(cell)
|
254
|
+
# raise CellInvalidCoordinatesException if outside_of_the_world?(cell) or negative_coordinates?(cell)
|
255
|
+
# @cells << cell
|
256
|
+
# end
|
257
|
+
|
258
|
+
# def revive(cell)
|
259
|
+
# raise CellIsAlreadyAliveException if exist?(cell) and cell.alive?
|
260
|
+
# cell.reborn!
|
261
|
+
# end
|
262
|
+
|
263
|
+
# def kill(cell)
|
264
|
+
# raise CellIsAlreadyDeadException if exist?(cell) and cell.dead?
|
265
|
+
# cell.die!
|
266
|
+
# end
|
267
|
+
|
268
|
+
# private
|
269
|
+
# def setup_board
|
270
|
+
# @board = Array.new(@width) do |row|
|
271
|
+
# Array.new(@height) do |column|
|
272
|
+
# Cell.new(row,column)
|
273
|
+
# end
|
274
|
+
# end
|
275
|
+
|
276
|
+
# @board.each do |row|
|
277
|
+
# row.each do |column|
|
278
|
+
# @cells << column
|
279
|
+
# end
|
280
|
+
# end
|
281
|
+
# end
|
282
|
+
|
283
|
+
# def update_cells(alives,deads)
|
284
|
+
# alives.each do |cell|
|
285
|
+
# cell.reborn!
|
286
|
+
# end
|
287
|
+
# deads.each do |cell|
|
288
|
+
# cell.die!
|
289
|
+
# end
|
290
|
+
# end
|
291
|
+
|
292
|
+
# def apply_rule_1(cell,number_of_live_neighbours)
|
293
|
+
# kill(cell) if cell.alive? and number_of_live_neighbours < 2
|
294
|
+
# end
|
295
|
+
|
296
|
+
# def apply_rule_2(cell)
|
297
|
+
# # revive(cell) if live_neighbours_of(cell).count == 2 or live_neighbours_of(cell).count == 3
|
298
|
+
# end
|
299
|
+
|
300
|
+
# def apply_rule_3(cell,number_of_live_neighbours)
|
301
|
+
# kill(cell) if cell.alive? and number_of_live_neighbours > 3
|
302
|
+
# end
|
303
|
+
|
304
|
+
# def apply_rule_4(cell,number_of_live_neighbours)
|
305
|
+
# revive(cell) if cell.dead? and number_of_live_neighbours == 3
|
306
|
+
# end
|
307
|
+
|
308
|
+
# def outside_of_the_world?(cell)
|
309
|
+
# (cell.x > @width) or (cell.y > @height)
|
310
|
+
# end
|
311
|
+
|
312
|
+
# def negative_coordinates?(cell)
|
313
|
+
# (cell.x < 0) or (cell.y < 0) and not @negative
|
314
|
+
# end
|
315
|
+
# end
|
316
|
+
end
|
data/lib/game_of_life.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require_relative 'game-of-life/exceptions'
|
2
|
+
require_relative 'game-of-life/cell'
|
3
|
+
require_relative 'game-of-life/world'
|
4
|
+
require_relative 'game-of-life/version'
|
5
|
+
require 'gosu'
|
6
|
+
|
7
|
+
module GameOfLife
|
8
|
+
class GameOfLifeWindow < Gosu::Window
|
9
|
+
def initialize(width=640, height=480)
|
10
|
+
@width, @height = width, height
|
11
|
+
super(@width, @height, false)
|
12
|
+
self.caption = 'The Game of Life'
|
13
|
+
|
14
|
+
# Variables
|
15
|
+
@num_columns = @width/5
|
16
|
+
@num_rows = @height/5
|
17
|
+
@column_width = @width/@num_columns
|
18
|
+
@row_height = @height/@num_rows
|
19
|
+
|
20
|
+
@white_color = Gosu::Color.new(0xffffffff)
|
21
|
+
@black_color = Gosu::Color.new(0xff000000)
|
22
|
+
@dead_color = Gosu::Color.new(0xff808080)
|
23
|
+
|
24
|
+
@world = World.new(@num_columns,@num_rows)
|
25
|
+
@world.seed!
|
26
|
+
end
|
27
|
+
|
28
|
+
def update
|
29
|
+
@world.rotate!
|
30
|
+
end
|
31
|
+
|
32
|
+
def draw
|
33
|
+
draw_cells
|
34
|
+
end
|
35
|
+
|
36
|
+
def needs_cursor?
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
40
|
+
def draw_cells
|
41
|
+
@world.cells.each do |cell|
|
42
|
+
if cell.alive?
|
43
|
+
draw_quad(
|
44
|
+
cell.x * @column_width, cell.y * @row_height, @white_color,
|
45
|
+
cell.x * @column_width + @column_width, cell.y * @row_height, @white_color,
|
46
|
+
cell.x * @column_width + @column_width, cell.y * @row_height + @row_height, @white_color,
|
47
|
+
cell.x * @column_width, cell.y * @row_height + @row_height, @white_color
|
48
|
+
)
|
49
|
+
else
|
50
|
+
draw_quad(
|
51
|
+
cell.x * @column_width, cell.y * @row_height, @black_color,
|
52
|
+
cell.x * @column_width + @column_width, cell.y * @row_height, @black_color,
|
53
|
+
cell.x * @column_width + @column_width, cell.y * @row_height + @row_height, @black_color,
|
54
|
+
cell.x * @column_width, cell.y * @row_height + @row_height, @black_color
|
55
|
+
)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require_relative '../../test_helper'
|
2
|
+
|
3
|
+
module GameOfLife
|
4
|
+
describe Cell do
|
5
|
+
describe "coordinates" do
|
6
|
+
it "coordinates" do
|
7
|
+
cell = Cell.new
|
8
|
+
cell.x.wont_be_nil
|
9
|
+
cell.y.wont_be_nil
|
10
|
+
end
|
11
|
+
it "should store coordinates" do
|
12
|
+
random_x = rand(11)
|
13
|
+
random_y = rand(11)
|
14
|
+
|
15
|
+
cell = Cell.new(random_x,random_y)
|
16
|
+
|
17
|
+
cell.x.must_equal random_x
|
18
|
+
cell.y.must_equal random_y
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "==" do
|
23
|
+
it "should be true if 2 cells has the same coordinates" do
|
24
|
+
cell_1 = Cell.new(1,2)
|
25
|
+
cell_2 = Cell.new(1,2)
|
26
|
+
|
27
|
+
cell_1.must_equal cell_2
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should be false if 2 cells has different coordinates" do
|
31
|
+
cell_1 = Cell.new(1,2)
|
32
|
+
cell_2 = Cell.new(2,1)
|
33
|
+
|
34
|
+
cell_1.wont_equal cell_2
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should be able to die" do
|
39
|
+
cell = Cell.new
|
40
|
+
|
41
|
+
cell.die!
|
42
|
+
cell.dead?.must_equal true
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should be able to reborn" do
|
46
|
+
cell = Cell.new(0,0,false)
|
47
|
+
|
48
|
+
cell.reborn!
|
49
|
+
cell.alive?.must_equal true
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should be dead or alive" do
|
53
|
+
cell = Cell.new
|
54
|
+
cell.alive.wont_be_nil
|
55
|
+
end
|
56
|
+
|
57
|
+
it "must have neighbours cells" do
|
58
|
+
cell = Cell.new
|
59
|
+
cell.neighbours.wont_be_nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require_relative '../../test_helper'
|
2
|
+
|
3
|
+
module GameOfLife
|
4
|
+
describe World do
|
5
|
+
describe "#initialize" do
|
6
|
+
it "should have a collection of cells" do
|
7
|
+
world = World.new(1,1)
|
8
|
+
|
9
|
+
world.cells.wont_be_nil
|
10
|
+
end
|
11
|
+
|
12
|
+
it "number of cells must be its width multiplied per its height" do
|
13
|
+
world = World.new(5,3)
|
14
|
+
world.cells.count.must_equal 5*3
|
15
|
+
end
|
16
|
+
|
17
|
+
it "must setup a matrix of cells, that represents the game board" do
|
18
|
+
world = World.new(3,3)
|
19
|
+
|
20
|
+
world.board.must_be_kind_of(Matrix)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should be able to randomize some cells" do
|
25
|
+
world = World.new(10,10)
|
26
|
+
|
27
|
+
world.seed!
|
28
|
+
|
29
|
+
world.live_cells.count.must_be(:>,0)
|
30
|
+
world.dead_cells.count.must_be(:>,0)
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#live_neighbours_of" do
|
34
|
+
it "should be able to count the live neighbours of a cell" do
|
35
|
+
world = World.new(3,3)
|
36
|
+
|
37
|
+
world.kill(0,0)
|
38
|
+
world.kill(1,0)
|
39
|
+
|
40
|
+
world.live_neighbours_of(1,1).count.must_equal 6
|
41
|
+
end
|
42
|
+
|
43
|
+
it "the cell (0,0) must have only 3 live neighbours" do
|
44
|
+
world = World.new(3,3)
|
45
|
+
|
46
|
+
world.live_neighbours_of(0,0).count.must_equal 3
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#make_it_live" do
|
51
|
+
it "should be able to make a dead cell live" do
|
52
|
+
world = World.new(2,2)
|
53
|
+
|
54
|
+
world.kill(1,1)
|
55
|
+
world.get(1,1).dead?.must_equal true
|
56
|
+
|
57
|
+
world.revive(1,1)
|
58
|
+
world.get(1,1).dead?.must_equal false
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#get" do
|
63
|
+
it "should return a given cell" do
|
64
|
+
world = World.new(2,2)
|
65
|
+
|
66
|
+
cell_to_be_found = Cell.new(1,1)
|
67
|
+
|
68
|
+
found_cell = world.get(1,1)
|
69
|
+
|
70
|
+
found_cell.must_equal cell_to_be_found
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "#kill" do
|
75
|
+
it "should be able to kill a cell" do
|
76
|
+
world = World.new(2,2)
|
77
|
+
|
78
|
+
world.dead_cells.count.must_equal 0
|
79
|
+
world.kill(1,1)
|
80
|
+
|
81
|
+
world.dead_cells.count.must_equal 1
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
module GameOfLife
|
4
|
+
describe "Rule #1: Any live cell with fewer than two live neighbours dies, as if caused by under-population." do
|
5
|
+
it "cells with 1 neighbour dies in the next day" do
|
6
|
+
world = World.new(2,2)
|
7
|
+
|
8
|
+
world.kill(0,0)
|
9
|
+
world.kill(1,1)
|
10
|
+
|
11
|
+
world.rotate!
|
12
|
+
|
13
|
+
world.cells.each do |cell|
|
14
|
+
cell.dead?.must_equal true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it "a cell with no live neighbours should die in the next day" do
|
19
|
+
world = World.new(3,3)
|
20
|
+
|
21
|
+
world.kill(0,0)
|
22
|
+
world.kill(1,0)
|
23
|
+
world.kill(2,0)
|
24
|
+
world.kill(0,1)
|
25
|
+
world.kill(2,1)
|
26
|
+
world.kill(0,2)
|
27
|
+
world.kill(1,2)
|
28
|
+
world.kill(2,2)
|
29
|
+
|
30
|
+
world.rotate!
|
31
|
+
|
32
|
+
world.get(1,1).dead?.must_equal true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
module GameOfLife
|
4
|
+
describe "Rule #4: Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction." do
|
5
|
+
it "a dead cell with 3 live neighbours will reborn in the next day" do
|
6
|
+
world = World.new(3,3)
|
7
|
+
|
8
|
+
# (0,2) (1,2) (2,2)
|
9
|
+
# (0,1) (1,1) (2,1)
|
10
|
+
# (0,0) (1,0) (2,0)
|
11
|
+
|
12
|
+
world.kill(1,2)
|
13
|
+
world.kill(2,2)
|
14
|
+
world.kill(2,1)
|
15
|
+
world.kill(2,0)
|
16
|
+
world.kill(1,0)
|
17
|
+
world.kill(1,1)
|
18
|
+
|
19
|
+
world.rotate!
|
20
|
+
|
21
|
+
world.get(1,1).alive?.must_equal true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
module GameOfLife
|
4
|
+
describe "Rule #2: Any live cell with two or three live neighbours lives on to the next generation." do
|
5
|
+
it "a cell with 2 live neighbours will be alive in the next day" do
|
6
|
+
world = World.new(3,3)
|
7
|
+
|
8
|
+
world.kill(0,2)
|
9
|
+
world.kill(1,2)
|
10
|
+
world.kill(2,2)
|
11
|
+
world.kill(0,0)
|
12
|
+
world.kill(1,0)
|
13
|
+
world.kill(2,0)
|
14
|
+
|
15
|
+
world.rotate!
|
16
|
+
|
17
|
+
world.get(1,1).alive?.must_equal true
|
18
|
+
end
|
19
|
+
|
20
|
+
it "a cell with 3 live neighbours will be alive in the next day" do
|
21
|
+
world = World.new(3,3)
|
22
|
+
|
23
|
+
world.kill(1,1)
|
24
|
+
world.kill(2,1)
|
25
|
+
world.kill(1,0)
|
26
|
+
world.kill(2,0)
|
27
|
+
|
28
|
+
world.rotate!
|
29
|
+
|
30
|
+
world.get(0,2).alive?.must_equal true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
module GameOfLife
|
4
|
+
describe "Rule #3: Any live cell with more than three live neighbours dies, as if by overcrowding." do
|
5
|
+
it "a cell with 4 live neighbours will die in the next day" do
|
6
|
+
world = World.new(3,3)
|
7
|
+
|
8
|
+
world.kill(0,2)
|
9
|
+
world.kill(1,2)
|
10
|
+
world.kill(2,2)
|
11
|
+
world.kill(2,0)
|
12
|
+
|
13
|
+
world.rotate!
|
14
|
+
|
15
|
+
world.get(1,1).dead?.must_equal true
|
16
|
+
end
|
17
|
+
|
18
|
+
it "a cell surrounded by live neighbours must die in the next day" do
|
19
|
+
world = World.new(3,3)
|
20
|
+
|
21
|
+
world.rotate!
|
22
|
+
|
23
|
+
world.get(1,1).dead?.must_equal true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: game-of-life
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Thiago Rocha
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-11-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: gosu
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: The Game of Life
|
42
|
+
email:
|
43
|
+
- kimo@kimo.io
|
44
|
+
executables:
|
45
|
+
- game-of-life
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- .ruby-version
|
50
|
+
- Gemfile
|
51
|
+
- Gemfile.lock
|
52
|
+
- Rakefile
|
53
|
+
- bin/game-of-life
|
54
|
+
- game-of-life.gemspec
|
55
|
+
- lib/game-of-life/cell.rb
|
56
|
+
- lib/game-of-life/exceptions.rb
|
57
|
+
- lib/game-of-life/version.rb
|
58
|
+
- lib/game-of-life/world.rb
|
59
|
+
- lib/game_of_life.rb
|
60
|
+
- test/lib/game-of-life/cell_test.rb
|
61
|
+
- test/lib/game-of-life/world_test.rb
|
62
|
+
- test/rules/first_rule_test.rb
|
63
|
+
- test/rules/fourth_rule_test.rb
|
64
|
+
- test/rules/second_rule_test.rb
|
65
|
+
- test/rules/third_rule_test.rb
|
66
|
+
- test/test_helper.rb
|
67
|
+
homepage: http://thiagokimo.github.io/game-of-life
|
68
|
+
licenses:
|
69
|
+
- MIT
|
70
|
+
metadata: {}
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ! '>='
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
requirements: []
|
86
|
+
rubyforge_project:
|
87
|
+
rubygems_version: 2.1.10
|
88
|
+
signing_key:
|
89
|
+
specification_version: 4
|
90
|
+
summary: A gem that shows random matches of Conway's Game of Life
|
91
|
+
test_files:
|
92
|
+
- test/lib/game-of-life/cell_test.rb
|
93
|
+
- test/lib/game-of-life/world_test.rb
|
94
|
+
- test/rules/first_rule_test.rb
|
95
|
+
- test/rules/fourth_rule_test.rb
|
96
|
+
- test/rules/second_rule_test.rb
|
97
|
+
- test/rules/third_rule_test.rb
|
98
|
+
- test/test_helper.rb
|