xo 1.0.0 → 1.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.
- checksums.yaml +8 -8
- data/Gemfile.lock +3 -1
- data/README.md +59 -23
- data/bin/xo +22 -27
- data/lib/xo.rb +1 -1
- data/lib/xo/ai/max_player.rb +22 -0
- data/lib/xo/ai/min_player.rb +22 -0
- data/lib/xo/ai/minimax.rb +47 -108
- data/lib/xo/ai/player.rb +44 -0
- data/lib/xo/engine.rb +32 -234
- data/lib/xo/engine/game_context.rb +28 -0
- data/lib/xo/engine/game_over.rb +33 -0
- data/lib/xo/engine/game_state.rb +21 -0
- data/lib/xo/engine/init.rb +24 -0
- data/lib/xo/engine/playing.rb +88 -0
- data/lib/xo/evaluator.rb +50 -66
- data/lib/xo/grid.rb +41 -93
- data/lib/xo/version.rb +1 -1
- data/spec/engine_spec.rb +323 -0
- data/spec/{xo/evaluator_spec.rb → evaluator_spec.rb} +25 -10
- data/spec/{xo/ai/geometric_grid_spec.rb → geometric_grid_spec.rb} +1 -3
- data/spec/{xo/grid_spec.rb → grid_spec.rb} +13 -16
- data/spec/{xo/ai/minimax_spec.rb → minimax_spec.rb} +0 -0
- data/xo.gemspec +3 -1
- metadata +36 -14
- data/lib/xo/ai.rb +0 -2
- data/spec/xo/engine_spec.rb +0 -331
@@ -4,10 +4,10 @@ module XO
|
|
4
4
|
|
5
5
|
describe Evaluator do
|
6
6
|
|
7
|
-
|
7
|
+
let (:evaluator) { Evaluator.instance }
|
8
|
+
let (:grid) { Grid.new }
|
8
9
|
|
9
|
-
|
10
|
-
let (:grid) { Grid.new }
|
10
|
+
describe "#analyze" do
|
11
11
|
|
12
12
|
describe "standard play" do
|
13
13
|
|
@@ -210,6 +210,11 @@ module XO
|
|
210
210
|
positions: [[1, 3], [2, 2], [3, 1]]
|
211
211
|
}]
|
212
212
|
}
|
213
|
+
|
214
|
+
evaluator.analyze(grid, Grid::X).must_equal result
|
215
|
+
|
216
|
+
result[:type] = :loser
|
217
|
+
evaluator.analyze(grid, Grid::O).must_equal result
|
213
218
|
end
|
214
219
|
end
|
215
220
|
|
@@ -227,13 +232,6 @@ module XO
|
|
227
232
|
end
|
228
233
|
end
|
229
234
|
|
230
|
-
describe "invalid token input" do
|
231
|
-
|
232
|
-
it "raises ArgumentError" do
|
233
|
-
proc { evaluator.analyze(Grid.new, :not_a_token) }.must_raise ArgumentError
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
235
|
describe "invalid grid input" do
|
238
236
|
|
239
237
|
it "returns too many moves ahead" do
|
@@ -256,6 +254,23 @@ module XO
|
|
256
254
|
evaluator.analyze(grid, Grid::O).must_equal result
|
257
255
|
end
|
258
256
|
end
|
257
|
+
|
258
|
+
describe "invalid token input" do
|
259
|
+
|
260
|
+
it "raises ArgumentError" do
|
261
|
+
proc { evaluator.analyze(Grid.new, :not_a_token) }.must_raise ArgumentError
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
describe ".xos" do
|
267
|
+
|
268
|
+
it "returns the number of x's and o's" do
|
269
|
+
xs, os = Evaluator.xos(Grid.new('xoxxo'))
|
270
|
+
|
271
|
+
xs.must_equal 3
|
272
|
+
os.must_equal 2
|
273
|
+
end
|
259
274
|
end
|
260
275
|
end
|
261
276
|
end
|
@@ -4,8 +4,6 @@ module XO::AI
|
|
4
4
|
|
5
5
|
describe GeometricGrid do
|
6
6
|
|
7
|
-
let(:grid) { GeometricGrid.new }
|
8
|
-
|
9
7
|
describe "#rotate" do
|
10
8
|
|
11
9
|
let (:grid) { GeometricGrid.new("xoooxxoxo") }
|
@@ -81,7 +79,7 @@ module XO::AI
|
|
81
79
|
end
|
82
80
|
end
|
83
81
|
|
84
|
-
describe "
|
82
|
+
describe "#==" do
|
85
83
|
|
86
84
|
it "is reflexive, symmetric and transitive" do
|
87
85
|
a = GeometricGrid.new('x')
|
@@ -4,6 +4,8 @@ module XO
|
|
4
4
|
|
5
5
|
describe Grid do
|
6
6
|
|
7
|
+
let(:grid) { Grid.new }
|
8
|
+
|
7
9
|
it "defines X" do
|
8
10
|
Grid::X.must_equal :x
|
9
11
|
end
|
@@ -12,6 +14,10 @@ module XO
|
|
12
14
|
Grid::O.must_equal :o
|
13
15
|
end
|
14
16
|
|
17
|
+
it "defines EMPTY" do
|
18
|
+
Grid::EMPTY.must_equal :e
|
19
|
+
end
|
20
|
+
|
15
21
|
it "has 3 rows" do
|
16
22
|
Grid::ROWS.must_equal 3
|
17
23
|
end
|
@@ -56,8 +62,8 @@ module XO
|
|
56
62
|
end
|
57
63
|
|
58
64
|
it "returns false otherwise" do
|
59
|
-
[nil, :e, '', ' '].each do
|
60
|
-
Grid.is_token?(
|
65
|
+
[nil, :e, '', ' '].each do |val|
|
66
|
+
Grid.is_token?(val).must_equal false
|
61
67
|
end
|
62
68
|
end
|
63
69
|
end
|
@@ -77,16 +83,11 @@ module XO
|
|
77
83
|
end
|
78
84
|
end
|
79
85
|
|
80
|
-
|
81
|
-
|
82
|
-
describe "an initial grid" do
|
86
|
+
describe ".new" do
|
83
87
|
|
84
|
-
it "is empty" do
|
88
|
+
it "is returns an empty grid when given no arguments" do
|
85
89
|
grid.empty?.must_equal true
|
86
90
|
end
|
87
|
-
end
|
88
|
-
|
89
|
-
describe "#new" do
|
90
91
|
|
91
92
|
it "can create a grid from a string" do
|
92
93
|
grid = Grid.new('xox o')
|
@@ -154,14 +155,14 @@ module XO
|
|
154
155
|
end
|
155
156
|
|
156
157
|
it "returns false when at least one position doesn't have a token" do
|
157
|
-
grid[1, 3] =
|
158
|
+
grid[1, 3] = Grid::EMPTY
|
158
159
|
grid.full?.must_equal false
|
159
160
|
end
|
160
161
|
end
|
161
162
|
|
162
163
|
describe "#[]=" do
|
163
164
|
|
164
|
-
it "sets a position to X, O or
|
165
|
+
it "sets a position to X, O or EMPTY" do
|
165
166
|
grid[2, 1] = Grid::X
|
166
167
|
grid[2, 1].must_equal Grid::X
|
167
168
|
|
@@ -169,7 +170,7 @@ module XO
|
|
169
170
|
grid[2, 2].must_equal Grid::O
|
170
171
|
|
171
172
|
grid[2, 3] = :anything_else
|
172
|
-
grid[2, 3].must_equal
|
173
|
+
grid[2, 3].must_equal Grid::EMPTY
|
173
174
|
end
|
174
175
|
|
175
176
|
it "raises IndexError when the position is off the grid" do
|
@@ -211,10 +212,6 @@ module XO
|
|
211
212
|
|
212
213
|
grid.empty?.must_equal true
|
213
214
|
end
|
214
|
-
|
215
|
-
it "returns self" do
|
216
|
-
grid.clear.must_be_same_as grid
|
217
|
-
end
|
218
215
|
end
|
219
216
|
|
220
217
|
describe "#each" do
|
File without changes
|
data/xo.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.author = 'Dwayne R. Crooks'
|
10
10
|
spec.email = ['me@dwaynecrooks.com']
|
11
11
|
spec.summary = %q{A Ruby library for Tic-tac-toe.}
|
12
|
-
spec.description = %q{A Ruby library that can be used to develop Tic-tac-toe game clients.}
|
12
|
+
spec.description = %q{A Ruby library for Tic-tac-toe that can be used to develop Tic-tac-toe game clients and servers.}
|
13
13
|
spec.homepage = 'https://github.com/dwayne/xo'
|
14
14
|
spec.license = 'MIT'
|
15
15
|
|
@@ -20,6 +20,8 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.required_ruby_version = '>= 1.9.3'
|
22
22
|
|
23
|
+
spec.add_runtime_dependency 'state_design_pattern', '~> 0.0.2'
|
24
|
+
|
23
25
|
spec.add_development_dependency 'rake', '~> 10.3'
|
24
26
|
spec.add_development_dependency 'minitest', '~> 5.3'
|
25
27
|
spec.add_development_dependency 'coveralls', '~> 0.7'
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dwayne R. Crooks
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-05-
|
11
|
+
date: 2014-05-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: state_design_pattern
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.0.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.0.2
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rake
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,7 +94,8 @@ dependencies:
|
|
80
94
|
- - ~>
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: '0.8'
|
83
|
-
description: A Ruby library that can be used to develop Tic-tac-toe
|
97
|
+
description: A Ruby library for Tic-tac-toe that can be used to develop Tic-tac-toe
|
98
|
+
game clients and servers.
|
84
99
|
email:
|
85
100
|
- me@dwaynecrooks.com
|
86
101
|
executables:
|
@@ -97,19 +112,26 @@ files:
|
|
97
112
|
- Rakefile
|
98
113
|
- bin/xo
|
99
114
|
- lib/xo.rb
|
100
|
-
- lib/xo/ai.rb
|
101
115
|
- lib/xo/ai/geometric_grid.rb
|
116
|
+
- lib/xo/ai/max_player.rb
|
117
|
+
- lib/xo/ai/min_player.rb
|
102
118
|
- lib/xo/ai/minimax.rb
|
119
|
+
- lib/xo/ai/player.rb
|
103
120
|
- lib/xo/engine.rb
|
121
|
+
- lib/xo/engine/game_context.rb
|
122
|
+
- lib/xo/engine/game_over.rb
|
123
|
+
- lib/xo/engine/game_state.rb
|
124
|
+
- lib/xo/engine/init.rb
|
125
|
+
- lib/xo/engine/playing.rb
|
104
126
|
- lib/xo/evaluator.rb
|
105
127
|
- lib/xo/grid.rb
|
106
128
|
- lib/xo/version.rb
|
129
|
+
- spec/engine_spec.rb
|
130
|
+
- spec/evaluator_spec.rb
|
131
|
+
- spec/geometric_grid_spec.rb
|
132
|
+
- spec/grid_spec.rb
|
133
|
+
- spec/minimax_spec.rb
|
107
134
|
- spec/spec_helper.rb
|
108
|
-
- spec/xo/ai/geometric_grid_spec.rb
|
109
|
-
- spec/xo/ai/minimax_spec.rb
|
110
|
-
- spec/xo/engine_spec.rb
|
111
|
-
- spec/xo/evaluator_spec.rb
|
112
|
-
- spec/xo/grid_spec.rb
|
113
135
|
- xo.gemspec
|
114
136
|
homepage: https://github.com/dwayne/xo
|
115
137
|
licenses:
|
@@ -136,10 +158,10 @@ signing_key:
|
|
136
158
|
specification_version: 4
|
137
159
|
summary: A Ruby library for Tic-tac-toe.
|
138
160
|
test_files:
|
161
|
+
- spec/engine_spec.rb
|
162
|
+
- spec/evaluator_spec.rb
|
163
|
+
- spec/geometric_grid_spec.rb
|
164
|
+
- spec/grid_spec.rb
|
165
|
+
- spec/minimax_spec.rb
|
139
166
|
- spec/spec_helper.rb
|
140
|
-
- spec/xo/ai/geometric_grid_spec.rb
|
141
|
-
- spec/xo/ai/minimax_spec.rb
|
142
|
-
- spec/xo/engine_spec.rb
|
143
|
-
- spec/xo/evaluator_spec.rb
|
144
|
-
- spec/xo/grid_spec.rb
|
145
167
|
has_rdoc:
|
data/lib/xo/ai.rb
DELETED
data/spec/xo/engine_spec.rb
DELETED
@@ -1,331 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module XO
|
4
|
-
|
5
|
-
describe Engine do
|
6
|
-
|
7
|
-
let (:engine) { Engine.new }
|
8
|
-
|
9
|
-
describe "its initial state" do
|
10
|
-
|
11
|
-
it "is in the :init state" do
|
12
|
-
engine.state.must_equal :init
|
13
|
-
end
|
14
|
-
|
15
|
-
it "is nobody's turn" do
|
16
|
-
engine.turn.must_equal :nobody
|
17
|
-
end
|
18
|
-
|
19
|
-
it "has an empty grid" do
|
20
|
-
engine.grid.empty?.must_equal true
|
21
|
-
end
|
22
|
-
|
23
|
-
it "has last event set to :new" do
|
24
|
-
event = engine.last_event
|
25
|
-
|
26
|
-
event[:name].must_equal :new
|
27
|
-
end
|
28
|
-
|
29
|
-
describe "#next_turn" do
|
30
|
-
|
31
|
-
it "returns :nobody" do
|
32
|
-
engine.next_turn.must_equal :nobody
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
describe "#grid" do
|
38
|
-
|
39
|
-
it "returns a copy of the underlying grid" do
|
40
|
-
grid = engine.grid
|
41
|
-
|
42
|
-
grid[1, 1] = Grid::X
|
43
|
-
|
44
|
-
engine.grid.open?(1, 1).must_equal true
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
describe "how the state machine works" do
|
49
|
-
|
50
|
-
describe "state :init" do
|
51
|
-
|
52
|
-
it "is in state :init" do
|
53
|
-
engine.state.must_equal :init
|
54
|
-
end
|
55
|
-
|
56
|
-
describe "#start" do
|
57
|
-
|
58
|
-
before { engine.start(Grid::X) }
|
59
|
-
|
60
|
-
it "changes state to :playing" do
|
61
|
-
engine.state.must_equal :playing
|
62
|
-
end
|
63
|
-
|
64
|
-
it "sets turn to the value passed in" do
|
65
|
-
engine.turn.must_equal Grid::X
|
66
|
-
end
|
67
|
-
|
68
|
-
it "starts with an empty grid" do
|
69
|
-
engine.grid.empty?.must_equal true
|
70
|
-
end
|
71
|
-
|
72
|
-
it "sets last event" do
|
73
|
-
event = engine.last_event
|
74
|
-
|
75
|
-
event[:name].must_equal :game_started
|
76
|
-
end
|
77
|
-
|
78
|
-
describe "#next_turn" do
|
79
|
-
|
80
|
-
it "returns O" do
|
81
|
-
engine.next_turn.must_equal Grid::O
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
it "only allows #start to be called" do
|
87
|
-
proc { engine.stop }.must_raise Engine::IllegalStateError
|
88
|
-
proc { engine.play(1, 1) }.must_raise Engine::IllegalStateError
|
89
|
-
proc { engine.continue_playing(Grid::X) }.must_raise Engine::IllegalStateError
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
describe "state :playing" do
|
94
|
-
|
95
|
-
before do
|
96
|
-
engine.start(Grid::X)
|
97
|
-
end
|
98
|
-
|
99
|
-
it "is in state :playing" do
|
100
|
-
engine.state.must_equal :playing
|
101
|
-
end
|
102
|
-
|
103
|
-
describe "#play" do
|
104
|
-
|
105
|
-
describe "valid moves" do
|
106
|
-
|
107
|
-
describe "when given (1, 1)" do
|
108
|
-
|
109
|
-
before { engine.play(1, 1) }
|
110
|
-
|
111
|
-
it "remains in state :playing" do
|
112
|
-
engine.state.must_equal :playing
|
113
|
-
end
|
114
|
-
|
115
|
-
it "sets turn to O" do
|
116
|
-
engine.turn.must_equal Grid::O
|
117
|
-
end
|
118
|
-
|
119
|
-
it "updates the grid at that position" do
|
120
|
-
engine.grid[1, 1].must_equal Grid::X
|
121
|
-
end
|
122
|
-
|
123
|
-
it "sets last event" do
|
124
|
-
event = engine.last_event
|
125
|
-
|
126
|
-
event[:name].must_equal :next_turn
|
127
|
-
event[:last_move][:turn].must_equal Grid::X
|
128
|
-
event[:last_move][:r].must_equal 1
|
129
|
-
event[:last_move][:c].must_equal 1
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
describe "when the next move results in the game being over" do
|
134
|
-
|
135
|
-
describe "winning" do
|
136
|
-
|
137
|
-
before do
|
138
|
-
engine.play(1, 1).play(2, 1).play(1, 2).play(2, 2).play(1, 3)
|
139
|
-
end
|
140
|
-
|
141
|
-
it "changes state to :game_over" do
|
142
|
-
engine.state.must_equal :game_over
|
143
|
-
end
|
144
|
-
|
145
|
-
it "sets turn to the winner" do
|
146
|
-
engine.turn.must_equal Grid::X
|
147
|
-
end
|
148
|
-
|
149
|
-
it "leaves the grid unchanged" do
|
150
|
-
engine.grid.inspect.must_equal 'xxxoo '
|
151
|
-
end
|
152
|
-
|
153
|
-
it "sets last event" do
|
154
|
-
event = engine.last_event
|
155
|
-
|
156
|
-
event[:name].must_equal :game_over
|
157
|
-
event[:type].must_equal :winner
|
158
|
-
event[:last_move][:turn].must_equal Grid::X
|
159
|
-
event[:last_move][:r].must_equal 1
|
160
|
-
event[:last_move][:c].must_equal 3
|
161
|
-
event[:details].must_equal [
|
162
|
-
{ where: :row, index: 1, positions: [[1, 1], [1, 2], [1, 3]] }
|
163
|
-
]
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
describe "squashed" do
|
168
|
-
|
169
|
-
before do
|
170
|
-
engine.play(1, 1).play(1, 2).play(1, 3).play(2, 2).play(3, 2).play(2, 1).play(2, 3).play(3, 3).play(3, 1)
|
171
|
-
end
|
172
|
-
|
173
|
-
it "changes state to :game_over" do
|
174
|
-
engine.state.must_equal :game_over
|
175
|
-
end
|
176
|
-
|
177
|
-
it "leaves turn set to the last one played" do
|
178
|
-
engine.turn.must_equal Grid::X
|
179
|
-
end
|
180
|
-
|
181
|
-
it "leaves the grid unchanged" do
|
182
|
-
engine.grid.inspect.must_equal 'xoxooxxxo'
|
183
|
-
end
|
184
|
-
|
185
|
-
it "sets last event" do
|
186
|
-
event = engine.last_event
|
187
|
-
|
188
|
-
event[:name].must_equal :game_over
|
189
|
-
event[:type].must_equal :squashed
|
190
|
-
event[:last_move][:turn].must_equal Grid::X
|
191
|
-
event[:last_move][:r].must_equal 3
|
192
|
-
event[:last_move][:c].must_equal 1
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
describe "invalid moves" do
|
199
|
-
|
200
|
-
describe "when given (0, 0)" do
|
201
|
-
|
202
|
-
it "sets last event to out of bounds" do
|
203
|
-
event = engine.play(0, 0).last_event
|
204
|
-
|
205
|
-
event[:name].must_equal :invalid_move
|
206
|
-
event[:type].must_equal :out_of_bounds
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
describe "when given (1, 1) and it already has a token there" do
|
211
|
-
|
212
|
-
it "sets last event to occupied" do
|
213
|
-
event = engine.play(1, 1).play(1, 1).last_event
|
214
|
-
|
215
|
-
event[:name].must_equal :invalid_move
|
216
|
-
event[:type].must_equal :occupied
|
217
|
-
end
|
218
|
-
end
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
|
-
describe "#stop" do
|
223
|
-
|
224
|
-
before { engine.stop }
|
225
|
-
|
226
|
-
it "changes state to :init" do
|
227
|
-
engine.state.must_equal :init
|
228
|
-
end
|
229
|
-
|
230
|
-
it "sets turn to :nobody" do
|
231
|
-
engine.turn.must_equal :nobody
|
232
|
-
end
|
233
|
-
|
234
|
-
it "clears the grid" do
|
235
|
-
engine.grid.empty?.must_equal true
|
236
|
-
end
|
237
|
-
|
238
|
-
it "sets last event" do
|
239
|
-
event = engine.last_event
|
240
|
-
|
241
|
-
event[:name].must_equal :game_stopped
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
it "only allows #play and #stop to be called" do
|
246
|
-
proc { engine.start(Grid::O) }.must_raise Engine::IllegalStateError
|
247
|
-
proc { engine.continue_playing(Grid::O) }.must_raise Engine::IllegalStateError
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
describe "state :game_over" do
|
252
|
-
|
253
|
-
before do
|
254
|
-
engine
|
255
|
-
.start(Grid::O)
|
256
|
-
.play(1, 1).play(2, 1).play(1, 2).play(2, 2).play(1, 3)
|
257
|
-
end
|
258
|
-
|
259
|
-
it "is in state :game_over" do
|
260
|
-
engine.state.must_equal :game_over
|
261
|
-
end
|
262
|
-
|
263
|
-
describe "#continue_playing" do
|
264
|
-
|
265
|
-
before { engine.continue_playing(Grid::O) }
|
266
|
-
|
267
|
-
it "changes state to :playing" do
|
268
|
-
engine.state.must_equal :playing
|
269
|
-
end
|
270
|
-
|
271
|
-
it "sets turn to O" do
|
272
|
-
engine.turn.must_equal Grid::O
|
273
|
-
end
|
274
|
-
|
275
|
-
it "clears the grid" do
|
276
|
-
engine.grid.empty?.must_equal true
|
277
|
-
end
|
278
|
-
|
279
|
-
it "sets last event" do
|
280
|
-
event = engine.last_event
|
281
|
-
|
282
|
-
event[:name].must_equal :game_started
|
283
|
-
event[:type].must_equal :continue_playing
|
284
|
-
end
|
285
|
-
end
|
286
|
-
|
287
|
-
describe "#stop" do
|
288
|
-
|
289
|
-
before { engine.stop }
|
290
|
-
|
291
|
-
it "changes state to :init" do
|
292
|
-
engine.state.must_equal :init
|
293
|
-
end
|
294
|
-
|
295
|
-
it "sets turn to :nobody" do
|
296
|
-
engine.turn.must_equal :nobody
|
297
|
-
end
|
298
|
-
|
299
|
-
it "clears the grid" do
|
300
|
-
engine.grid.empty?.must_equal true
|
301
|
-
end
|
302
|
-
|
303
|
-
it "sets last event" do
|
304
|
-
event = engine.last_event
|
305
|
-
|
306
|
-
event[:name].must_equal :game_stopped
|
307
|
-
end
|
308
|
-
end
|
309
|
-
|
310
|
-
it "only allows #continue_playing and #stop to be called" do
|
311
|
-
proc { engine.start(Grid::X) }.must_raise Engine::IllegalStateError
|
312
|
-
proc { engine.play(1, 1) }.must_raise Engine::IllegalStateError
|
313
|
-
end
|
314
|
-
end
|
315
|
-
end
|
316
|
-
|
317
|
-
describe "#start with invalid input" do
|
318
|
-
|
319
|
-
it "raises an ArgumentError" do
|
320
|
-
proc { engine.start(:invalid_input) }.must_raise ArgumentError
|
321
|
-
end
|
322
|
-
end
|
323
|
-
|
324
|
-
describe "#continue_playing with invalid input" do
|
325
|
-
|
326
|
-
it "raises an ArgumentError" do
|
327
|
-
proc { engine.continue_playing(:invalid_input) }.must_raise ArgumentError
|
328
|
-
end
|
329
|
-
end
|
330
|
-
end
|
331
|
-
end
|