erics_tic_tac_toe 0.1.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,19 @@
1
+ require 'test_helper'
2
+
3
+ class GamePresentorTest < MiniTest::Unit::TestCase
4
+ def setup
5
+ @game = TicTacToe::Game.new
6
+ @presentor = TicTacToe::GamePresentor.new(@game)
7
+ end
8
+
9
+ def test_grid
10
+ assert_equal [%w(1 2 3), %w(4 5 6), %w(7 8 9)], @presentor.grid
11
+ end
12
+
13
+ def test_grid_with_moves
14
+ @game = TicTacToe::Game.new([['x', nil, nil], [nil, nil, nil], [nil, nil, nil]])
15
+ @presentor = TicTacToe::GamePresentor.new(@game)
16
+
17
+ assert_equal [%w(x 2 3), %w(4 5 6), %w(7 8 9)], @presentor.grid
18
+ end
19
+ end
data/test/game_test.rb ADDED
@@ -0,0 +1,79 @@
1
+ require 'test_helper'
2
+
3
+
4
+ class GameTest < MiniTest::Unit::TestCase
5
+
6
+ class PlayerMock
7
+ def initialize(move)
8
+ @move = move
9
+ end
10
+
11
+ def get_move(_board)
12
+ move = @move
13
+ @move = nil
14
+ move
15
+ end
16
+
17
+ def has_next_move?
18
+ !!@move
19
+ end
20
+
21
+ def letter
22
+ 'x'
23
+ end
24
+ end
25
+
26
+ def test_grid
27
+ game = TicTacToe::Game.new
28
+
29
+ assert_equal game.grid, empty_grid
30
+ end
31
+
32
+ def test_an_empty_game_is_not_solved
33
+ game = TicTacToe::Game.new
34
+
35
+ refute game.solved?
36
+ end
37
+
38
+ def test_a_full_grid_is_cats
39
+ # x o x
40
+ # x o x
41
+ # o x o
42
+ game = TicTacToe::Game.new([%w(x o x), %w(x o x), %w(o x o)])
43
+
44
+ assert game.cats?
45
+ end
46
+
47
+ def test_winner
48
+ game = TicTacToe::Game.new([%w(x x x), [nil,nil,nil], [nil, nil, nil]],
49
+ PlayerMock.new(nil), PlayerMock.new(nil))
50
+
51
+ assert_equal 'x', game.winner
52
+ end
53
+
54
+ def test_setting_a_players_move
55
+ game = TicTacToe::Game.new(empty_grid, PlayerMock.new('1'), PlayerMock.new(nil))
56
+ game.start
57
+
58
+ assert_equal 'x', game.board.get_cell(0, 0)
59
+ end
60
+
61
+ def test_set_move_via_computer
62
+ game = TicTacToe::Game.new(empty_grid, PlayerMock.new([0,0]), PlayerMock.new([2,2]))
63
+ game.start
64
+
65
+ assert_equal 7, game.board.empty_positions.size
66
+ end
67
+
68
+ def test_skip_a_players_turn
69
+ game = TicTacToe::Game.new(empty_grid, PlayerMock.new([0,0]), PlayerMock.new(nil))
70
+ game.start
71
+
72
+ assert game.board.only_one?
73
+ end
74
+
75
+
76
+ def empty_grid(size=3)
77
+ Array.new(size) { Array.new(size) { nil } }
78
+ end
79
+ end
@@ -0,0 +1,12 @@
1
+ require 'test_helper'
2
+
3
+ class PlayerPresenterTest < MiniTest::Unit::TestCase
4
+ def setup
5
+ @player_mock = OpenStruct.new(letter: 'x', type: 'mock')
6
+ end
7
+
8
+ def test_move_json
9
+ assert_equal({letter: 'x', type: 'mock', move: '1'}.to_json,
10
+ TicTacToe::PlayerPresenter.new(@player_mock).move_json('1'))
11
+ end
12
+ end
@@ -0,0 +1,57 @@
1
+ require 'test_helper'
2
+
3
+ class BoardMock; end
4
+
5
+ class PlayerTest < MiniTest::Unit::TestCase
6
+
7
+ def test_build_human_player
8
+ assert_equal TicTacToe::HumanPlayer,
9
+ TicTacToe::Player.build('type' => 'human').class
10
+ end
11
+
12
+ def test_build_computer_player
13
+ assert_equal TicTacToe::ComputerPlayer,
14
+ TicTacToe::Player.build('type' => 'computer').class
15
+ end
16
+ end
17
+
18
+ module SharedPlayerTests
19
+ def test_gets_move
20
+ assert_equal [0, 0], @player.get_move(BoardMock.new)
21
+ end
22
+
23
+ def test_letter
24
+ assert_equal 'x', @player.letter
25
+ end
26
+
27
+ def test_has_next_move
28
+ assert @player.has_next_move?
29
+ end
30
+
31
+ def test_has_type
32
+ refute @player.type.nil?
33
+ end
34
+
35
+ end
36
+
37
+ class HumanPlayerTest < MiniTest::Unit::TestCase
38
+ def setup
39
+ @player = TicTacToe::HumanPlayer.new('letter' => "x", 'move' => [0,0])
40
+ end
41
+
42
+ include SharedPlayerTests
43
+ end
44
+
45
+
46
+ class ComputerPlayerTest < MiniTest::Unit::TestCase
47
+ class SolverMock
48
+ def solve
49
+ [0, 0]
50
+ end
51
+ end
52
+ def setup
53
+ @player = TicTacToe::ComputerPlayer.new({'letter' => "x"}, SolverMock)
54
+ end
55
+
56
+ include SharedPlayerTests
57
+ end
@@ -0,0 +1,53 @@
1
+ require 'test_helper'
2
+
3
+ class PotentialStateTest < MiniTest::Unit::TestCase
4
+ def test_solved
5
+ set_grid([ ['x', 'x', 'x'], [nil, nil, nil], [nil, nil, nil] ])
6
+ assert @state.solved?
7
+ end
8
+
9
+ def test_fork_exists
10
+ set_grid([ ['x', nil, 'x'], [nil, 'x', nil], [nil, nil, nil] ])
11
+ assert @state.fork_exists?
12
+
13
+ set_grid([ ['x', nil, 'x'], [nil, 'o', nil], ['x', nil, nil] ])
14
+ assert @state.fork_exists?
15
+
16
+ set_grid([ ['o', nil, 'o'], [nil, 'x', nil], ['o', nil, nil] ])
17
+ refute @state.fork_exists?
18
+
19
+ end
20
+
21
+ def test_forking_positions
22
+ # o | 2 | x |
23
+ # 4 | o | 6 |
24
+ # x | 8 | 9 |
25
+ set_grid([ ['o', nil, 'x'], [nil, 'o', nil], ['x', nil, nil] ])
26
+ assert @state.forking_positions.size == 1
27
+ end
28
+
29
+ def test_can_win_next_turn
30
+ set_grid([[ 'x', nil, 'x'], [nil, nil, nil], [nil, nil, nil] ])
31
+ assert @state.can_win_next_turn?
32
+
33
+ # 1 | 2 | x
34
+ # 4 | o | 6
35
+ # 7 | x | x
36
+ set_grid([[ nil, nil, 'x'], [nil, 'o', nil], [nil, 'x', 'x'] ])
37
+ assert @state.can_win_next_turn?
38
+
39
+ # o | 2 | x |
40
+ # 4 | o | 6 |
41
+ # x | 8 | 9 |
42
+ set_grid([ ['o', nil, 'x'], [nil, 'o', nil], ['x', nil, nil] ])
43
+ refute @state.can_win_next_turn?
44
+ end
45
+
46
+ private
47
+
48
+ def set_grid(grid)
49
+ board = TicTacToe::Board.new
50
+ board.grid = grid
51
+ @state = TicTacToe::ThreeByThree::PotentialState.new(board, 'x')
52
+ end
53
+ end
data/test/solver_test.rb CHANGED
@@ -1,131 +1,140 @@
1
1
  require 'test_helper'
2
2
 
3
- class SolverTest < MiniTest::Unit::TestCase
4
- def setup
5
- TicTacToe::Solver.instance_eval { attr_accessor :strategy } # For testing
6
- @solver = TicTacToe::Solver.new(TicTacToe::Board.new, 'x')
7
- @solver.strategy.class.instance_eval { attr_accessor :implementation } # For testing
8
- @solver.strategy.implementation.class.instance_eval { attr_accessor :board } # For testing
3
+ module SharedSolverTests
4
+ def test_win_horizontally
5
+ refute @board.solved?
6
+
7
+ # Will win, when there is a winning move
8
+ set_grid([[ 'x', 'x', nil],
9
+ [ 'o', 'o', nil],
10
+ [ 'x', 'o', nil] ])
11
+ refute @board.solved? # Is not solved yet
12
+ solve!
13
+ assert !!@board.solved?, "Could not solve the board" # Solved it
14
+ assert_equal 'x', @board.get_cell(2, 0) # Placed the right letter
9
15
  end
10
16
 
11
- def test_win_next_move
12
- refute board.solved?
17
+ def test_wins_across
13
18
 
14
- # Will win, when there is a winning move
15
- set_grid([[ 'x', 'x', nil], [nil, nil, nil], [nil, nil, nil] ])
16
- refute board.solved? # Is not solved yet
17
- @solver.next_move!
18
- assert board.solved? # Solved it
19
- assert_equal 'x', board.get_cell(2, 0) # Placed the right letter
20
-
21
- set_grid([[ 'x', nil, nil], [nil, 'x', nil], [nil, nil, nil] ])
22
- refute board.solved?
23
- @solver.next_move!
24
- assert board.solved?
25
- assert_equal 'x', board.get_cell(2, 2)
19
+ set_grid([[ 'x', 'o', nil],
20
+ [ nil, 'x', nil],
21
+ [ 'o', nil, nil] ])
22
+ refute @board.solved?
23
+ solve!
24
+ assert !!@board.solved?
25
+ assert_equal 'x', @board.get_cell(2, 2)
26
+ end
27
+
28
+ def test_wins_vertically
26
29
 
27
- set_grid([[ 'x', nil, nil], [nil, nil, nil], ['x', nil, nil] ])
28
- refute board.solved?
29
- @solver.next_move!
30
- assert board.solved?
31
- assert_equal 'x', board.get_cell(0, 1)
30
+ set_grid([[ 'x', nil, 'o'],
31
+ [nil, 'o', 'o'],
32
+ [ 'x', nil, nil] ])
33
+ refute @board.solved?
34
+ solve!
35
+ assert !!@board.solved?
36
+ assert_equal 'x', @board.get_cell(0, 1)
37
+ end
38
+
39
+ def test_does_not_win_unsolvable_board
32
40
 
33
41
  # Can not win when there is no winning move
34
42
  set_grid([[ 'o', nil, nil], [nil, nil, nil], ['o', nil, nil] ])
35
- refute board.solved?
36
- @solver.next_move!
37
- refute board.solved?
43
+ refute @board.solved?
44
+ solve!
45
+ refute @board.solved?
38
46
  end
39
47
 
40
- def test_block_next_move
41
- refute board.solved?
48
+ def test_blocks_horizontally
49
+ refute @board.solved?
42
50
 
43
51
  # Will block when the opponent is about to win
44
- set_grid([ ['o', 'o', nil], [nil, nil,nil], [nil,nil,nil]])
45
- refute board.solved?
46
- @solver.next_move!
47
- refute board.solved?
52
+ set_grid([ ['o', 'o', nil],
53
+ [nil, 'x', nil],
54
+ [nil, 'x', nil]])
55
+ refute @board.solved?
56
+ solve!
57
+ refute @board.solved?
48
58
  # Placed the right letter at the right place
49
- assert_equal 'x', board.get_cell(2, 0)
59
+ assert_equal 'x', @board.get_cell(2, 0)
50
60
  end
51
61
 
62
+ def test_blocks_vertically
63
+
64
+ set_grid([ ['x', 'o', nil],
65
+ [nil, nil, nil],
66
+ [nil, 'o', nil]])
67
+ solve!
68
+ assert_equal 'x', @board.get_cell(1, 1)
69
+ end
52
70
 
53
- def test_fork_next_move
54
- refute board.solved?
71
+
72
+ def test_forks_in_middle
73
+ refute @board.solved?
55
74
 
56
75
  # Place letter in place where next turn is an automatic win
57
- set_grid([ ['x', nil, nil], [nil, 'o',nil], [nil,nil,'x']])
58
- refute board.solved?
59
- @solver.next_move!
60
- refute board.solved?
61
- assert_equal 'x', board.get_cell(2, 0)
76
+ set_grid([ ['x', 'o', 'x'],
77
+ [nil, nil, 'o'],
78
+ [nil, nil, nil]])
79
+ refute @board.solved?
80
+ solve!
81
+ refute @board.solved?
82
+ correct_cells = @board.get_cell(1, 1) || @board.get_cell(0, 2)
83
+ assert !!correct_cells
84
+ end
85
+
86
+ def test_forks_in_corner
62
87
 
63
88
  # 1 | 2 | x
64
89
  # 4 | o | 6
65
90
  # 7 | x | 9 <--
66
- set_grid([ [nil, nil, 'x'], [nil, 'o',nil], [nil,'x',nil]])
67
- refute board.solved?
68
- @solver.next_move!
69
- refute board.solved?
70
- assert_equal 'x', board.get_cell(2, 2)
91
+ set_grid([ [nil, 'o', 'x'],
92
+ [nil, 'o', nil],
93
+ [nil, 'x', nil]])
94
+ refute @board.solved?
95
+ solve!
96
+ refute @board.solved?
97
+ assert_equal 'x', @board.get_cell(2, 2)
71
98
  end
72
99
 
73
- def test_block_fork_next_move
74
- # Will block an opponent if they will have a change to fork next turn
75
-
76
- # 1 | 2 | o
77
- # 4 | x | 6
78
- # 7 | o | 9 <--
79
- set_grid([ [nil, nil, 'o'], [nil, 'x',nil], [nil,'o',nil]])
80
- refute board.solved?
81
- @solver.next_move!
82
- refute board.solved?
83
- assert_equal 'x', board.get_cell(2, 2)
84
-
100
+ def test_does_not_create_fork
85
101
  # 1 | 2 | o
86
102
  # 4 | x | 6
87
103
  # o | 8 | 9
88
- set_grid([[nil,nil,'o'],[nil,'x',nil],['o',nil,nil]])
89
- @solver.next_move!
90
- assert_nil board.get_cell(2,2)
91
- assert_nil board.get_cell(0,0)
104
+ set_grid([[nil,nil,'o'],
105
+ [nil,'x',nil],
106
+ ['o',nil,nil]])
107
+ solve!
108
+ assert_nil @board.get_cell(2,2)
109
+ assert_nil @board.get_cell(0,0)
110
+ end
111
+
112
+ def test_does_not_create_fork_in_the_future
92
113
 
93
114
  # x | 2 | 3
94
115
  # 4 | o | 6
95
116
  # 7 | 8 | o
96
117
  set_grid([ ['x',nil,nil], [nil,'o',nil], [nil,nil,'o'] ])
97
- @solver.next_move!
98
- assert_nil board.get_cell(1, 0)
99
- assert_nil board.get_cell(0, 1)
100
- assert_nil board.get_cell(2, 1)
101
- assert_nil board.get_cell(1, 2)
118
+ solve!
119
+ assert_nil @board.get_cell(1, 0)
120
+ assert_nil @board.get_cell(0, 1)
121
+ assert_nil @board.get_cell(2, 1)
122
+ assert_nil @board.get_cell(1, 2)
102
123
  end
103
124
 
104
- def test_center
105
- # Will play in the center if its an empty board
106
- assert board.empty?
107
- @solver.next_move!
108
- assert_equal 'x', board.center_cell
109
- assert board.only_one?
125
+ def test_does_not_create_fork_in_the_far_future
126
+ set_grid([['o', nil, nil], [nil, nil, nil], [nil, nil, nil]])
127
+ solve!
128
+ assert_nil @board.get_cell(0, 2)
110
129
  end
111
-
112
- def test_oposite_corner
113
- # 1 | 2 | o
114
- # 4 | x | 6
115
- # 7 | 8 | 9
116
- set_grid([[nil,nil,'o'],[nil,'x',nil],[nil,nil,nil]])
117
- @solver.next_move!
118
- assert_equal 'x', board.get_cell(0, 2)
119
130
 
120
- set_grid([['o',nil,nil],[nil,'x',nil],[nil,nil,nil]])
121
- @solver.next_move!
122
- assert_equal 'x', board.get_cell(2, 2)
123
- end
124
131
 
125
132
  def test_empty_corner
126
133
  set_grid([[nil,nil,nil],[nil,'o',nil],[nil,nil,nil]])
127
- @solver.next_move!
128
- assert_equal 'x', board.get_cell(0,0)
134
+ solve!
135
+ played_corner = @board.get_cell(0,0) || @board.get_cell(0,2) ||
136
+ @board.get_cell(2,0) || @board.get_cell(2,2)
137
+ assert played_corner
129
138
  end
130
139
 
131
140
  def test_any_empty_position
@@ -133,17 +142,84 @@ class SolverTest < MiniTest::Unit::TestCase
133
142
  # o | x | 6
134
143
  # x | o | x
135
144
  set_grid([['o', 'x', 'o'],['o','x',nil],['x','o','x']])
136
- @solver.next_move!
137
- assert_equal 'x', board.get_cell(2, 1)
145
+ solve!
146
+ assert_equal 'x', @board.get_cell(2, 1)
147
+ end
148
+
149
+ def test_raises_exception_on_full_board
150
+ set_grid([%w(x o x), %w(o o x), %w(o x o)])
151
+ assert_raises(RuntimeError) { solve! }
138
152
  end
139
153
 
140
154
  private
141
155
 
142
156
  def set_grid(grid)
143
- board.instance_variable_set("@grid", grid)
157
+ @board.grid = grid
144
158
  end
145
159
 
146
- def board
147
- @solver.strategy.implementation.board
160
+ def solve!
161
+ @board.play_at(*@solver.solve, 'x')
162
+ end
163
+ end
164
+
165
+ class MinimaxSolverTest < MiniTest::Unit::TestCase
166
+ def setup
167
+ @board = TicTacToe::Board.new
168
+ @solver = TicTacToe::MinimaxStrategy.new(@board, 'x')
169
+ end
170
+
171
+ include SharedSolverTests
172
+ end
173
+
174
+ class ThreeByThreeSolverTest < MiniTest::Unit::TestCase
175
+ def setup
176
+ @board = TicTacToe::Board.new
177
+ @solver = TicTacToe::ThreeByThreeStrategy.new(@board, 'x')
178
+ end
179
+
180
+ include SharedSolverTests
181
+
182
+ def test_block_fork
183
+ set_grid([['o', nil, nil], ['x', 'o', nil], [nil, nil, 'x']])
184
+ solve!
185
+ assert_equal 'x', @board.get_cell(1, 0)
186
+ end
187
+
188
+ def test_center
189
+ # Will play in the center if its an empty @board
190
+ assert @board.empty?
191
+ solve!
192
+ assert_equal 'x', @board.get_cell(@board.size/2, @board.size/2)
193
+ assert @board.only_one?
194
+ end
195
+
196
+ def test_opposite_corner
197
+ # 1 | 2 | o
198
+ # 4 | x | 6
199
+ # 7 | 8 | 9
200
+ set_grid([[nil,nil,'o'],[nil,'x',nil],[nil,nil,nil]])
201
+ solve!
202
+ assert_equal 'x', @board.get_cell(0, 2)
203
+
204
+ set_grid([['o',nil,nil],[nil,'x',nil],[nil,nil,nil]])
205
+ solve!
206
+ assert_equal 'x', @board.get_cell(2, 2)
207
+ end
208
+
209
+ def test_corners
210
+ set_grid([['x', nil, nil], [nil, 'o', nil], [nil, nil, nil]])
211
+ solve!
212
+ assert_equal 'x', @board.get_cell(2,0)
213
+
214
+ set_grid([['x', 'o', 'x'], [nil, 'o', nil], ['o', 'x', nil]])
215
+ solve!
216
+ assert_equal 'x', @board.get_cell(2, 2)
217
+
218
+ # x | o | x
219
+ # o | o | x
220
+ # | x | o
221
+ set_grid([['x', 'o', 'x'], ['o', 'o', 'x'], [nil, 'x', 'o']])
222
+ solve!
223
+ assert_equal 'x', @board.get_cell(0, 2)
148
224
  end
149
225
  end