bashrw-ttt 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.
- data/bin/play.rb +10 -0
- data/lib/bashrw-ttt.rb +3 -0
- data/lib/ttt/ai.rb +33 -0
- data/lib/ttt/ai_easy.rb +17 -0
- data/lib/ttt/ai_hard.rb +21 -0
- data/lib/ttt/ai_medium.rb +21 -0
- data/lib/ttt/ai_medium_back.rb +58 -0
- data/lib/ttt/board.rb +37 -0
- data/lib/ttt/config_helper.rb +53 -0
- data/lib/ttt/config_options.rb +27 -0
- data/lib/ttt/context.rb +214 -0
- data/lib/ttt/four_by_four.rb +62 -0
- data/lib/ttt/game.rb +94 -0
- data/lib/ttt/game_history.rb +37 -0
- data/lib/ttt/game_interactor.rb +126 -0
- data/lib/ttt/human.rb +12 -0
- data/lib/ttt/interfaces/cli/lib/cli/board_selection.rb +34 -0
- data/lib/ttt/interfaces/cli/lib/cli/cli_game.rb +186 -0
- data/lib/ttt/interfaces/cli/lib/cli/cli_presenter.rb +216 -0
- data/lib/ttt/interfaces/cli/lib/cli/clio.rb +17 -0
- data/lib/ttt/interfaces/cli/lib/cli/play_again.rb +38 -0
- data/lib/ttt/interfaces/cli/lib/cli/player_selection.rb +43 -0
- data/lib/ttt/interfaces/cli/lib/cli/selection.rb +8 -0
- data/lib/ttt/interfaces/cli/lib/cli/walk_history.rb +48 -0
- data/lib/ttt/interfaces/cli/spec/cli/board_selection_spec.rb +29 -0
- data/lib/ttt/interfaces/cli/spec/cli/cli_game_spec.rb +376 -0
- data/lib/ttt/interfaces/cli/spec/cli/cli_presenter_spec.rb +147 -0
- data/lib/ttt/interfaces/cli/spec/cli/play_again_spec.rb +39 -0
- data/lib/ttt/interfaces/cli/spec/cli/player_selection_spec.rb +62 -0
- data/lib/ttt/interfaces/cli/spec/cli/walk_history_spec.rb +115 -0
- data/lib/ttt/interfaces/cli/spec/spec_helper.rb +14 -0
- data/lib/ttt/interfaces/limelight/four_by_four/props.rb +1 -0
- data/lib/ttt/interfaces/limelight/four_by_four/styles.rb +74 -0
- data/lib/ttt/interfaces/limelight/four_by_four_finished/props.rb +1 -0
- data/lib/ttt/interfaces/limelight/four_by_four_finished/styles.rb +74 -0
- data/lib/ttt/interfaces/limelight/game_list/players/load_button.rb +10 -0
- data/lib/ttt/interfaces/limelight/game_list/props.rb +17 -0
- data/lib/ttt/interfaces/limelight/game_list/styles.rb +8 -0
- data/lib/ttt/interfaces/limelight/main_menu/players/exit_ttt.rb +3 -0
- data/lib/ttt/interfaces/limelight/main_menu/players/load_game.rb +3 -0
- data/lib/ttt/interfaces/limelight/main_menu/players/new_game.rb +3 -0
- data/lib/ttt/interfaces/limelight/main_menu/props.rb +17 -0
- data/lib/ttt/interfaces/limelight/new_game/players/board_type.rb +1 -0
- data/lib/ttt/interfaces/limelight/new_game/players/new_game.rb +5 -0
- data/lib/ttt/interfaces/limelight/new_game/players/player_type.rb +1 -0
- data/lib/ttt/interfaces/limelight/new_game/players/setup_button.rb +21 -0
- data/lib/ttt/interfaces/limelight/new_game/props.rb +21 -0
- data/lib/ttt/interfaces/limelight/new_game/styles.rb +23 -0
- data/lib/ttt/interfaces/limelight/partials/board_partial.rb +14 -0
- data/lib/ttt/interfaces/limelight/partials/menu_button_partial.rb +5 -0
- data/lib/ttt/interfaces/limelight/partials/move_history_partial.rb +6 -0
- data/lib/ttt/interfaces/limelight/partials/title_history_partial.rb +10 -0
- data/lib/ttt/interfaces/limelight/players/board.rb +3 -0
- data/lib/ttt/interfaces/limelight/players/game.rb +4 -0
- data/lib/ttt/interfaces/limelight/players/generic_move_history.rb +5 -0
- data/lib/ttt/interfaces/limelight/players/generic_player.rb +8 -0
- data/lib/ttt/interfaces/limelight/players/left_button.rb +3 -0
- data/lib/ttt/interfaces/limelight/players/main_menu.rb +3 -0
- data/lib/ttt/interfaces/limelight/players/right_button.rb +3 -0
- data/lib/ttt/interfaces/limelight/playscripts/game_playscript.rb +169 -0
- data/lib/ttt/interfaces/limelight/production.rb +14 -0
- data/lib/ttt/interfaces/limelight/spec/game_playscript_spec.rb +218 -0
- data/lib/ttt/interfaces/limelight/spec/main_menu/main_menu_spec.rb +38 -0
- data/lib/ttt/interfaces/limelight/spec/new_game/new_game_spec.rb +45 -0
- data/lib/ttt/interfaces/limelight/spec/spec_helper.rb +8 -0
- data/lib/ttt/interfaces/limelight/stages.rb +6 -0
- data/lib/ttt/interfaces/limelight/styles.rb +119 -0
- data/lib/ttt/interfaces/limelight/three_by_three/props.rb +1 -0
- data/lib/ttt/interfaces/limelight/three_by_three/styles.rb +39 -0
- data/lib/ttt/interfaces/limelight/three_by_three_by_three/props.rb +1 -0
- data/lib/ttt/interfaces/limelight/three_by_three_by_three/styles.rb +119 -0
- data/lib/ttt/interfaces/limelight/three_by_three_by_three_finished/props.rb +1 -0
- data/lib/ttt/interfaces/limelight/three_by_three_by_three_finished/styles.rb +119 -0
- data/lib/ttt/interfaces/limelight/three_by_three_finished/props.rb +1 -0
- data/lib/ttt/interfaces/limelight/three_by_three_finished/styles.rb +39 -0
- data/lib/ttt/interfaces/rails/app/controllers/application_controller.rb +3 -0
- data/lib/ttt/interfaces/rails/app/controllers/ttt_games_controller.rb +86 -0
- data/lib/ttt/interfaces/rails/app/helpers/application_helper.rb +2 -0
- data/lib/ttt/interfaces/rails/app/models/ttt_game.rb +34 -0
- data/lib/ttt/interfaces/rails/app/presenters/web_game_presenter.rb +159 -0
- data/lib/ttt/interfaces/rails/autotest/discover.rb +1 -0
- data/lib/ttt/interfaces/rails/config/application.rb +67 -0
- data/lib/ttt/interfaces/rails/config/boot.rb +6 -0
- data/lib/ttt/interfaces/rails/config/environment.rb +5 -0
- data/lib/ttt/interfaces/rails/config/environments/development.rb +37 -0
- data/lib/ttt/interfaces/rails/config/environments/production.rb +67 -0
- data/lib/ttt/interfaces/rails/config/environments/test.rb +37 -0
- data/lib/ttt/interfaces/rails/config/initializers/backtrace_silencers.rb +7 -0
- data/lib/ttt/interfaces/rails/config/initializers/inflections.rb +15 -0
- data/lib/ttt/interfaces/rails/config/initializers/mime_types.rb +5 -0
- data/lib/ttt/interfaces/rails/config/initializers/secret_token.rb +7 -0
- data/lib/ttt/interfaces/rails/config/initializers/session_store.rb +8 -0
- data/lib/ttt/interfaces/rails/config/initializers/wrap_parameters.rb +14 -0
- data/lib/ttt/interfaces/rails/config/routes.rb +49 -0
- data/lib/ttt/interfaces/rails/db/schema.rb +28 -0
- data/lib/ttt/interfaces/rails/db/seeds.rb +7 -0
- data/lib/ttt/interfaces/rails/spec/controllers/ttt_games_controller_spec.rb +211 -0
- data/lib/ttt/interfaces/rails/spec/models/ttt_game_spec.rb +76 -0
- data/lib/ttt/interfaces/rails/spec/presenters/web_game_presenter_spec.rb +52 -0
- data/lib/ttt/interfaces/rails/spec/spec_helper.rb +13 -0
- data/lib/ttt/interfaces/web_interface/html_generator.rb +76 -0
- data/lib/ttt/interfaces/web_interface/web_game_presenter.rb +0 -0
- data/lib/ttt/minimax.rb +46 -0
- data/lib/ttt/move_history.rb +10 -0
- data/lib/ttt/move_traverser.rb +49 -0
- data/lib/ttt/player.rb +15 -0
- data/lib/ttt/riak_db.rb +53 -0
- data/lib/ttt/setup.rb +59 -0
- data/lib/ttt/three_by_three.rb +35 -0
- data/lib/ttt/three_by_three_by_three.rb +37 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/ttt/ai_easy_spec.rb +15 -0
- data/spec/ttt/ai_hard_spec.rb +76 -0
- data/spec/ttt/ai_medium_spec.rb +65 -0
- data/spec/ttt/ai_spec.rb +50 -0
- data/spec/ttt/board_spec.rb +96 -0
- data/spec/ttt/config_helper_spec.rb +54 -0
- data/spec/ttt/context_spec.rb +398 -0
- data/spec/ttt/four_by_four_spec.rb +112 -0
- data/spec/ttt/game_history_spec.rb +41 -0
- data/spec/ttt/game_interactor_spec.rb +197 -0
- data/spec/ttt/game_spec.rb +246 -0
- data/spec/ttt/human_spec.rb +18 -0
- data/spec/ttt/move_history_spec.rb +13 -0
- data/spec/ttt/move_traverser_spec.rb +75 -0
- data/spec/ttt/player_spec.rb +13 -0
- data/spec/ttt/riak_db_spec.rb +64 -0
- data/spec/ttt/setup_spec.rb +63 -0
- data/spec/ttt/three_by_three_by_three_spec.rb +130 -0
- data/spec/ttt/three_by_three_spec.rb +110 -0
- metadata +239 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module TTT
|
|
4
|
+
describe GameInteractor do
|
|
5
|
+
let(:game) { Game.new(player1: Human.new(side: "x"), player2: Human.new(side: "o"), board: ThreeByThree.new, history: GameHistory.new) }
|
|
6
|
+
let(:ai_game){ Game.new(player1: AIEasy.new(side: "x"), player2: AIEasy.new(side: "o"), board: ThreeByThree.new, history: GameHistory.new) }
|
|
7
|
+
let(:bucket) { "game_interactor_bucket" }
|
|
8
|
+
let(:db) { RiakDB.new(bucket: bucket, port: 8091) }
|
|
9
|
+
let(:gi) { GameInteractor.new(db) }
|
|
10
|
+
|
|
11
|
+
describe "#ai_move?" do
|
|
12
|
+
it "returns true if the next move is from an AI player" do
|
|
13
|
+
gi.ai_move?(ai_game).should == true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "returns false if the next move is not from an AI player" do
|
|
17
|
+
gi.ai_move?(game).should == false
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe "#ai_move" do
|
|
22
|
+
it "directs the ai to move, side effect is board is updated and current player switched" do
|
|
23
|
+
cur_player = ai_game.current_player
|
|
24
|
+
board = ai_game.board.board.dup
|
|
25
|
+
id = gi.add_game(ai_game)
|
|
26
|
+
gi.ai_move(id, ai_game)
|
|
27
|
+
board.should_not == ai_game.board.board
|
|
28
|
+
cur_player.should_not.eql? ai_game.current_player
|
|
29
|
+
ai_game.history.history.length.should == 1
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "does nothing if the current player is a human player" do
|
|
33
|
+
cur_player = game.current_player
|
|
34
|
+
board = game.board.board.dup
|
|
35
|
+
id = gi.add_game(game)
|
|
36
|
+
gi.ai_move(id, game)
|
|
37
|
+
board.should == game.board.board
|
|
38
|
+
cur_player.should.eql? game.current_player
|
|
39
|
+
game.history.history.length.should == 0
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe "#finished?" do
|
|
44
|
+
it "returns true if the game is over" do
|
|
45
|
+
game.board.board = %w(a b c d e f g h i)
|
|
46
|
+
gi.finished?(game).should == true
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "returns false if the game is not over" do
|
|
50
|
+
gi.finished?(game).should == false
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe "#winner?" do
|
|
55
|
+
it "returns true if a winner is found" do
|
|
56
|
+
game.board.board = %w(x x x x x x x x x)
|
|
57
|
+
gi.winner?(game).should == true
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "returns false if a winner is not found" do
|
|
61
|
+
gi.winner?(game).should == false
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe "#winner" do
|
|
66
|
+
it "returns 'Player 1' when the current player is player 2" do
|
|
67
|
+
game.switch_player()
|
|
68
|
+
gi.winner(game).should == "Player 1"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "returns 'Player 2' when the current player is player 1" do
|
|
72
|
+
gi.winner(game).should == "Player 2"
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
describe "#draw?" do
|
|
77
|
+
it "returns true if the game is a draw" do
|
|
78
|
+
game.board.board = %w(a b c d e f g h i)
|
|
79
|
+
gi.draw?(game).should == true
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it "returns false if the game is not a draw" do
|
|
83
|
+
game.board.board = Array.new(9, " ")
|
|
84
|
+
gi.draw?(game).should == false
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
describe "#which_board" do
|
|
89
|
+
it "returns `three_by_three` when the board type is 3x3" do
|
|
90
|
+
gi.which_board(game).should == "three_by_three"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "returns `four_by_four` when the board type is 4x4" do
|
|
94
|
+
game.board = FourByFour.new
|
|
95
|
+
gi.which_board(game).should == "four_by_four"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "returns `three_by_three_by_three` when the board type is 3x3x3" do
|
|
99
|
+
game.board = ThreeByThreeByThree.new
|
|
100
|
+
gi.which_board(game).should == "three_by_three_by_three"
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
describe "#valid_move?" do
|
|
105
|
+
it "returns true if the move input by the user is a valid move for the current game board" do
|
|
106
|
+
game.board.board = Array.new(9, " ")
|
|
107
|
+
gi.valid_move?(game, 1).should == true
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "returns false if the move input by the user is not a valid move for the current game board" do
|
|
111
|
+
game.board.board = %w(a b c d e f g h i)
|
|
112
|
+
gi.valid_move?(game, 1).should == false
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
describe "#get_history" do
|
|
117
|
+
it "returns an empty array when it's a new game (no move history)" do
|
|
118
|
+
gi.get_history(game).should == []
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "returns an array with one move history object after the first move" do
|
|
122
|
+
game.record_move(1)
|
|
123
|
+
move_hist_arr = gi.get_history(game)
|
|
124
|
+
move_hist_arr.length.should == 1
|
|
125
|
+
move_hist_arr[0].side.should == "x"
|
|
126
|
+
move_hist_arr[0].move.should == 1
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "returns an array of two move history objects after the second move" do
|
|
130
|
+
game.record_move(1)
|
|
131
|
+
game.switch_player
|
|
132
|
+
game.record_move(2)
|
|
133
|
+
move_hist_arr = gi.get_history(game)
|
|
134
|
+
move_hist_arr.length.should == 2
|
|
135
|
+
move_hist_arr[0].side.should == "x"
|
|
136
|
+
move_hist_arr[1].side.should == "o"
|
|
137
|
+
move_hist_arr[0].move.should == 1
|
|
138
|
+
move_hist_arr[1].move.should == 2
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
describe "#switch_player" do
|
|
143
|
+
it "sets the other player as the current player" do
|
|
144
|
+
game.current_player = game.player1
|
|
145
|
+
player2 = game.player2
|
|
146
|
+
gi.switch_player(game)
|
|
147
|
+
game.current_player.eql? player2
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
describe "#which_current_player?" do
|
|
152
|
+
it "returns 'Player 1' if the current player is player 1" do
|
|
153
|
+
game.current_player = game.player1
|
|
154
|
+
gi.which_current_player?(game).should == "Player 1"
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
it "returns 'Player 2' if the current player is player 2" do
|
|
158
|
+
game.current_player = game.player2
|
|
159
|
+
gi.which_current_player?(game).should == "Player 2"
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
describe "#board_arr" do
|
|
164
|
+
it "returns the board array" do
|
|
165
|
+
gi.board(game).should == Array.new(9, " ")
|
|
166
|
+
game.board[] = %w(a b c d e f g h i)
|
|
167
|
+
gi.board(game).should == %w(a b c d e f g h i)
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
describe "#mark_move" do
|
|
172
|
+
it "marks a move for a game" do
|
|
173
|
+
game.board[] = Array.new(9, " ")
|
|
174
|
+
gi.mark_move(game, 0, 'x')
|
|
175
|
+
game.board[].should == ['x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
|
|
176
|
+
gi.mark_move(game, 1, 'o')
|
|
177
|
+
game.board[].should == ['x', 'o', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
describe "#record_move" do
|
|
182
|
+
it "records the move for the game" do
|
|
183
|
+
gi.record_move(game, 0, 'x')
|
|
184
|
+
gi.get_history(game)[0].move.should == 0
|
|
185
|
+
gi.get_history(game)[0].side.should == 'x'
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
describe "#not_finished" do
|
|
190
|
+
it "returns the opposite of #finished?" do
|
|
191
|
+
gi.not_finished?(game).should == true
|
|
192
|
+
game.board[] = %w(a b c d e f g h i)
|
|
193
|
+
gi.not_finished?(game).should == false
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'stringio'
|
|
3
|
+
|
|
4
|
+
module TTT
|
|
5
|
+
describe Game do
|
|
6
|
+
let(:setup) { Setup.new }
|
|
7
|
+
let(:players) { setup.players }
|
|
8
|
+
let(:boards) { setup.boards }
|
|
9
|
+
let(:game) { setup.new_game(player1: players.first, player2: players.first, board: boards.first) }
|
|
10
|
+
|
|
11
|
+
describe "#initialize" do
|
|
12
|
+
it "instantiated with a player1" do
|
|
13
|
+
game.player1.should_not == nil
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "instantiaed with a player1 with side 'x'" do
|
|
17
|
+
game.player1.side.should == "x"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "instantiated with a player2" do
|
|
21
|
+
game.player2.should_not == nil
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "instantiated with a player2 with side 'o'" do
|
|
25
|
+
game.player2.side.should == "o"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "has an empty board" do
|
|
29
|
+
game.board.should be_empty
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe "#current_player" do
|
|
34
|
+
it "is player1 at the beginning of a game" do
|
|
35
|
+
game.current_player.eql? game.player1
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "is player2 on the next turn" do
|
|
39
|
+
game.switch_player
|
|
40
|
+
game.current_player.eql? game.player2
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
describe "#mark_move" do
|
|
45
|
+
it "marks a move on the game board" do
|
|
46
|
+
game.mark_move(1)
|
|
47
|
+
game.board[].should == [" ", "x", " ", " ", " ", " ", " ", " ", " "]
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
describe "#switch_player" do
|
|
52
|
+
it "switches current player to the opposite player" do
|
|
53
|
+
game.switch_player
|
|
54
|
+
game.current_player.eql? game.player2
|
|
55
|
+
game.switch_player
|
|
56
|
+
game.current_player.eql? game.player1
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
describe "#next_move" do
|
|
61
|
+
before(:each) do
|
|
62
|
+
game.player1 = AIEasy.new(side: "x")
|
|
63
|
+
game.current_player = game.player1
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "prompts the AI to move next if the AI is the current player" do
|
|
67
|
+
game.player1.should_receive(:move).and_return(0)
|
|
68
|
+
game.next_move
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "returns an updated board reflecting the AI's move" do
|
|
72
|
+
game.player1.should_receive(:move).and_return(0)
|
|
73
|
+
game.next_move
|
|
74
|
+
game.board[].should == ["x", " ", " ", " ", " ", " ", " ", " ", " "]
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
describe "#record_move" do
|
|
79
|
+
it "invokes record_move on history" do
|
|
80
|
+
game.history.should_receive(:record_move)
|
|
81
|
+
game.record_move(0)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
describe "#show_history" do
|
|
86
|
+
it "invokes show on history" do
|
|
87
|
+
game.history.should_receive(:show)
|
|
88
|
+
game.show_history
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
describe "#which_board?" do
|
|
93
|
+
it "returns `three_by_three` when the board type is 3x3" do
|
|
94
|
+
game.board = ThreeByThree.new
|
|
95
|
+
game.which_board.should == "three_by_three"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "returns `four_by_four` when the board type is 4x4" do
|
|
99
|
+
game.board = FourByFour.new
|
|
100
|
+
game.which_board.should == "four_by_four"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "returns `three_by_three_by_three` when the board type is 3x3x3" do
|
|
104
|
+
game.board = ThreeByThreeByThree.new
|
|
105
|
+
game.which_board.should == "three_by_three_by_three"
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
describe "#which_current_player" do
|
|
110
|
+
it "returns the current player" do
|
|
111
|
+
game.which_current_player?.should == "Player 1"
|
|
112
|
+
game.which_current_player?.should_not == "Player 2"
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
describe "#last_player?" do
|
|
117
|
+
it "returns the previous player" do
|
|
118
|
+
game.last_player.should == "Player 2"
|
|
119
|
+
game.last_player.should_not == "Player 1"
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
describe "#finished?" do
|
|
124
|
+
it "returns true if the game board is finished" do
|
|
125
|
+
game.board[] = Array.new(9, 'a')
|
|
126
|
+
game.finished?.should == true
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "returns false if the game board is not finished" do
|
|
130
|
+
game.finished?.should == false
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
describe "#not_finished?" do
|
|
135
|
+
it "returns true if the game board is not finished" do
|
|
136
|
+
game.not_finished?.should == true
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it "returns false if the game board is finished" do
|
|
140
|
+
game.board[] = Array.new(9, 'a')
|
|
141
|
+
game.not_finished?.should == false
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
describe "#winner?" do
|
|
146
|
+
it "returns true if the game board has a winner" do
|
|
147
|
+
game.board[] = Array.new(9, 'x')
|
|
148
|
+
game.winner?.should == true
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it "returns false if the game board does not have a winner" do
|
|
152
|
+
game.board[] = Array.new(9, ' ')
|
|
153
|
+
game.winner?.should == false
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
describe "#draw?" do
|
|
158
|
+
it "returns true if the game board has a draw" do
|
|
159
|
+
game.board[] = %w(a b c d e f g h i)
|
|
160
|
+
game.draw?.should == true
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
it "returns false if the game board does not have a draw" do
|
|
164
|
+
game.board[] = Array.new(9, ' ')
|
|
165
|
+
game.draw?.should == false
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
describe "#board_arr" do
|
|
170
|
+
it "returns the board array of the current game instance" do
|
|
171
|
+
game.board_arr.class.should == Array
|
|
172
|
+
game.board[] = Array.new(9, 'a')
|
|
173
|
+
game.board_arr.should == Array.new(9, 'a')
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
describe "#adjust_move_index" do
|
|
178
|
+
it "adjusts the game_history#move_traverser move_index" do
|
|
179
|
+
game.record_move(1, 'x')
|
|
180
|
+
game.history.move_traverser.move_index.should == 1
|
|
181
|
+
game.adjust_move_index(-1)
|
|
182
|
+
game.history.move_traverser.move_index.should == 0
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
describe "#initialize_history" do
|
|
187
|
+
it "resets the game_history to the length of the GameHistory#history array" do
|
|
188
|
+
game.record_move(1, 'x')
|
|
189
|
+
game.history.move_traverser.move_index.should == 1
|
|
190
|
+
game.adjust_move_index(-1)
|
|
191
|
+
game.history.move_traverser.move_index.should == 0
|
|
192
|
+
game.initialize_history
|
|
193
|
+
game.history.move_traverser.move_index.should == 1
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
describe "#get_history_board" do
|
|
198
|
+
it "returns the game board at the specified move number" do
|
|
199
|
+
game.record_move(0, 'o')
|
|
200
|
+
game.record_move(1, 'x')
|
|
201
|
+
game.record_move(2, 'x')
|
|
202
|
+
game.record_move(3, 'x')
|
|
203
|
+
game.record_move(4, 'x')
|
|
204
|
+
game.record_move(5, 'o')
|
|
205
|
+
game.record_move(6, 'o')
|
|
206
|
+
game.record_move(7, 'o')
|
|
207
|
+
game.record_move(8, 'o')
|
|
208
|
+
game.get_history_board(1).should == ['o', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
|
|
209
|
+
game.get_history_board(2).should == ['o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
|
|
210
|
+
game.get_history_board(3).should == ['o', 'x', 'x', ' ', ' ', ' ', ' ', ' ', ' ']
|
|
211
|
+
game.get_history_board(4).should == ['o', 'x', 'x', 'x', ' ', ' ', ' ', ' ', ' ']
|
|
212
|
+
game.get_history_board(5).should == ['o', 'x', 'x', 'x', 'x', ' ', ' ', ' ', ' ']
|
|
213
|
+
game.get_history_board(6).should == ['o', 'x', 'x', 'x', 'x', 'o', ' ', ' ', ' ']
|
|
214
|
+
game.get_history_board(7).should == ['o', 'x', 'x', 'x', 'x', 'o', 'o', ' ', ' ']
|
|
215
|
+
game.get_history_board(8).should == ['o', 'x', 'x', 'x', 'x', 'o', 'o', 'o', ' ']
|
|
216
|
+
game.get_history_board(9).should == ['o', 'x', 'x', 'x', 'x', 'o', 'o', 'o', 'o']
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
describe "#valid_move" do
|
|
221
|
+
before(:each) do
|
|
222
|
+
game.board.board = ['x', 'o', 'x', 'o', ' ', ' ', ' ', ' ', ' ']
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
it "returns true when a move is possible" do
|
|
226
|
+
game.valid_move?(4).should == true
|
|
227
|
+
game.valid_move?(5).should == true
|
|
228
|
+
game.valid_move?(6).should == true
|
|
229
|
+
game.valid_move?(7).should == true
|
|
230
|
+
game.valid_move?(8).should == true
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
it "returns false when a move the move's intended square has already been taken" do
|
|
234
|
+
game.valid_move?(0).should == false
|
|
235
|
+
game.valid_move?(1).should == false
|
|
236
|
+
game.valid_move?(2).should == false
|
|
237
|
+
game.valid_move?(3).should == false
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
it "returns false when input is not a number within 0 and the board length" do
|
|
241
|
+
game.valid_move?('z').should == false
|
|
242
|
+
game.valid_move?(123.123).should == false
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module TTT
|
|
2
|
+
describe Human do
|
|
3
|
+
let(:human) { Human.new(side: "x") }
|
|
4
|
+
let(:game) { Game.new(view: view, board: board) }
|
|
5
|
+
|
|
6
|
+
describe "#no_gui?" do
|
|
7
|
+
it "returns false" do
|
|
8
|
+
human.no_gui?.should == false
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe "#prompt" do
|
|
13
|
+
it "returns 'Player thinking'" do
|
|
14
|
+
human.prompt.should == "Enter move:"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module TTT
|
|
4
|
+
describe MoveHistory do
|
|
5
|
+
describe "#new" do
|
|
6
|
+
it "returns a new TTT::MoveHistory object with side and move attributes" do
|
|
7
|
+
move_history = described_class.new(side: "x", move: 0)
|
|
8
|
+
move_history.side.should == "x"
|
|
9
|
+
move_history.move.should == 0
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module TTT
|
|
4
|
+
describe MoveTraverser do
|
|
5
|
+
let(:board) { ThreeByThree.new }
|
|
6
|
+
let(:game_history) { GameHistory.new }
|
|
7
|
+
let(:traverser) { game_history.move_traverser }
|
|
8
|
+
|
|
9
|
+
context do
|
|
10
|
+
before(:each) do
|
|
11
|
+
game_history.record_move(0, 'x')
|
|
12
|
+
game_history.record_move(1, 'o')
|
|
13
|
+
game_history.record_move(2, 'x')
|
|
14
|
+
game_history.record_move(3, 'o')
|
|
15
|
+
game_history.record_move(4, 'x')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe "#adjust_move_index" do
|
|
19
|
+
|
|
20
|
+
it "moves backward in the move history by 1 when its invoked with -1" do
|
|
21
|
+
traverser.adjust_move_index(-1)
|
|
22
|
+
traverser.move_index.should == 4
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "moves forward in the move history by 1 when its invoked with 1" do
|
|
26
|
+
traverser.move_index = 4
|
|
27
|
+
traverser.adjust_move_index(1)
|
|
28
|
+
traverser.move_index.should == 5
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "moves backward in the move history by 2 when its invoked with -2" do
|
|
32
|
+
traverser.adjust_move_index(-2)
|
|
33
|
+
traverser.move_index.should == 3
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "moves forward in the move history by 2 when its invoked with 2" do
|
|
37
|
+
traverser.move_index = 2
|
|
38
|
+
traverser.adjust_move_index(2)
|
|
39
|
+
traverser.move_index.should == 4
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "cannot move backwards beyond move index 0" do
|
|
43
|
+
traverser.move_index = 0
|
|
44
|
+
traverser.adjust_move_index(-1)
|
|
45
|
+
traverser.move_index.should == 0
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "cannot move beyond the max length" do
|
|
49
|
+
traverser.move_index = traverser.max_length
|
|
50
|
+
traverser.adjust_move_index(100)
|
|
51
|
+
traverser.move_index.should == traverser.max_length
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
describe "#history_board_builder" do
|
|
56
|
+
it "returns a board array representing the moves made up to move_number in history" do
|
|
57
|
+
traverser.history_board_builder(board, 3).should == ['x', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ']
|
|
58
|
+
board.board = Array.new(9, ' ')
|
|
59
|
+
traverser.history_board_builder(board, 5).should == ['x', 'o', 'x', 'o', 'x', ' ', ' ', ' ', ' ']
|
|
60
|
+
board.board = Array.new(9, ' ')
|
|
61
|
+
traverser.history_board_builder(board, 0).should == Array.new(9, ' ')
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "does not alter the original board" do
|
|
65
|
+
traverser.history_board_builder(board, 3).should_not == board.board
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "does not alter the original game history" do
|
|
69
|
+
original_history = traverser.game_history.history
|
|
70
|
+
traverser.game_history.history.should == original_history
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module TTT
|
|
4
|
+
describe RiakDB do
|
|
5
|
+
Riak.disable_list_keys_warnings = true
|
|
6
|
+
let(:setup) { Setup.new }
|
|
7
|
+
let(:players) { setup.players }
|
|
8
|
+
let(:boards) { setup.boards }
|
|
9
|
+
let(:game) { setup.new_game(player1: players.first, player2: players.first, board: boards.first) }
|
|
10
|
+
let(:riak) { setup.new_db }
|
|
11
|
+
let(:bucket) { riak.bucket }
|
|
12
|
+
|
|
13
|
+
describe "#new" do
|
|
14
|
+
it "establishes a connection with the Riak cluster" do
|
|
15
|
+
riak.client.should_not be_nil
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe "#add_game" do
|
|
20
|
+
it "adds a game to the game_list bucket" do
|
|
21
|
+
@id = riak.add_game(game)
|
|
22
|
+
riak.client[bucket].get(@id).data[:game].should_not == nil
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe "#game_list" do
|
|
27
|
+
it "returns a list of games available in the specified game bucket" do
|
|
28
|
+
num_keys_in_db = riak.client[bucket].keys.length
|
|
29
|
+
riak.game_list.length.should == num_keys_in_db
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe "#get_game" do
|
|
34
|
+
it "returns a game object from the Riak datastore" do
|
|
35
|
+
cur_id = riak.cur_id
|
|
36
|
+
riak.get_game(cur_id).class.should == Game
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "returns nil if there is no game at the specified id" do
|
|
40
|
+
riak.get_game(10000000000000000000).should == nil
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
describe "#save_game" do
|
|
45
|
+
it "saves an existing game to the Riak datastore" do
|
|
46
|
+
cur_id = riak.cur_id
|
|
47
|
+
new_game = riak.get_game(cur_id)
|
|
48
|
+
new_game.player1.side = "test"
|
|
49
|
+
riak.save_game(cur_id, new_game)
|
|
50
|
+
after_save = riak.get_game(cur_id)
|
|
51
|
+
new_game.player1.side.should == after_save.player1.side
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
describe "#delete_game" do
|
|
56
|
+
it "deletes an existing game from the Riak datastore" do
|
|
57
|
+
id = riak.add_game(game)
|
|
58
|
+
riak.get_game(id).class.should == Game
|
|
59
|
+
riak.delete_game(id)
|
|
60
|
+
riak.client[bucket].get_or_new(id).data.should == nil
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'ttt/config_options'
|
|
3
|
+
|
|
4
|
+
module TTT
|
|
5
|
+
describe Setup do
|
|
6
|
+
let(:setup) { Setup.new }
|
|
7
|
+
|
|
8
|
+
describe "#new_game" do
|
|
9
|
+
it "returns a new game object after instantiating the players, board, db and game history" do
|
|
10
|
+
game = setup.new_game(player1: "Human", player2: "AI Easy", board: "3x3")
|
|
11
|
+
game.player1.class.should == Human
|
|
12
|
+
game.player2.class.should == AIEasy
|
|
13
|
+
game.player1.side.should == "x"
|
|
14
|
+
game.player2.side.should == "o"
|
|
15
|
+
game.board.class.should == ThreeByThree
|
|
16
|
+
game.history.should_not be_nil
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe "#new_db" do
|
|
21
|
+
it "returns a new db object" do
|
|
22
|
+
db = setup.new_db
|
|
23
|
+
db.should respond_to(:client)
|
|
24
|
+
db.should respond_to(:bucket)
|
|
25
|
+
db.should respond_to(:cur_id)
|
|
26
|
+
db.should respond_to(:save_game)
|
|
27
|
+
db.should respond_to(:get_game)
|
|
28
|
+
db.should respond_to(:add_game)
|
|
29
|
+
db.should respond_to(:game_list)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe "#players" do
|
|
34
|
+
it "returns a list of player types supported by the library" do
|
|
35
|
+
setup.players.should == ConfigOptions::HUMAN_READABLE_PLAYERS
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
describe "#boards" do
|
|
40
|
+
it "returns a list of board types supported by the library" do
|
|
41
|
+
setup.boards.should == ConfigOptions::HUMAN_READABLE_BOARDS
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe "#db" do
|
|
46
|
+
it "returns the db const specified in the config options file" do
|
|
47
|
+
setup.db.should == ConfigOptions::DB
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
describe "#interactor" do
|
|
52
|
+
it "returns the interactor const specified in the config options file" do
|
|
53
|
+
setup.interactor.should == ConfigOptions::INTERACTOR
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
describe "#new_interactor" do
|
|
58
|
+
it "returns an instance of a game interactor" do
|
|
59
|
+
setup.new_interactor.class.should == GameInteractor
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|