game-of-life 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|