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.
Files changed (131) hide show
  1. data/bin/play.rb +10 -0
  2. data/lib/bashrw-ttt.rb +3 -0
  3. data/lib/ttt/ai.rb +33 -0
  4. data/lib/ttt/ai_easy.rb +17 -0
  5. data/lib/ttt/ai_hard.rb +21 -0
  6. data/lib/ttt/ai_medium.rb +21 -0
  7. data/lib/ttt/ai_medium_back.rb +58 -0
  8. data/lib/ttt/board.rb +37 -0
  9. data/lib/ttt/config_helper.rb +53 -0
  10. data/lib/ttt/config_options.rb +27 -0
  11. data/lib/ttt/context.rb +214 -0
  12. data/lib/ttt/four_by_four.rb +62 -0
  13. data/lib/ttt/game.rb +94 -0
  14. data/lib/ttt/game_history.rb +37 -0
  15. data/lib/ttt/game_interactor.rb +126 -0
  16. data/lib/ttt/human.rb +12 -0
  17. data/lib/ttt/interfaces/cli/lib/cli/board_selection.rb +34 -0
  18. data/lib/ttt/interfaces/cli/lib/cli/cli_game.rb +186 -0
  19. data/lib/ttt/interfaces/cli/lib/cli/cli_presenter.rb +216 -0
  20. data/lib/ttt/interfaces/cli/lib/cli/clio.rb +17 -0
  21. data/lib/ttt/interfaces/cli/lib/cli/play_again.rb +38 -0
  22. data/lib/ttt/interfaces/cli/lib/cli/player_selection.rb +43 -0
  23. data/lib/ttt/interfaces/cli/lib/cli/selection.rb +8 -0
  24. data/lib/ttt/interfaces/cli/lib/cli/walk_history.rb +48 -0
  25. data/lib/ttt/interfaces/cli/spec/cli/board_selection_spec.rb +29 -0
  26. data/lib/ttt/interfaces/cli/spec/cli/cli_game_spec.rb +376 -0
  27. data/lib/ttt/interfaces/cli/spec/cli/cli_presenter_spec.rb +147 -0
  28. data/lib/ttt/interfaces/cli/spec/cli/play_again_spec.rb +39 -0
  29. data/lib/ttt/interfaces/cli/spec/cli/player_selection_spec.rb +62 -0
  30. data/lib/ttt/interfaces/cli/spec/cli/walk_history_spec.rb +115 -0
  31. data/lib/ttt/interfaces/cli/spec/spec_helper.rb +14 -0
  32. data/lib/ttt/interfaces/limelight/four_by_four/props.rb +1 -0
  33. data/lib/ttt/interfaces/limelight/four_by_four/styles.rb +74 -0
  34. data/lib/ttt/interfaces/limelight/four_by_four_finished/props.rb +1 -0
  35. data/lib/ttt/interfaces/limelight/four_by_four_finished/styles.rb +74 -0
  36. data/lib/ttt/interfaces/limelight/game_list/players/load_button.rb +10 -0
  37. data/lib/ttt/interfaces/limelight/game_list/props.rb +17 -0
  38. data/lib/ttt/interfaces/limelight/game_list/styles.rb +8 -0
  39. data/lib/ttt/interfaces/limelight/main_menu/players/exit_ttt.rb +3 -0
  40. data/lib/ttt/interfaces/limelight/main_menu/players/load_game.rb +3 -0
  41. data/lib/ttt/interfaces/limelight/main_menu/players/new_game.rb +3 -0
  42. data/lib/ttt/interfaces/limelight/main_menu/props.rb +17 -0
  43. data/lib/ttt/interfaces/limelight/new_game/players/board_type.rb +1 -0
  44. data/lib/ttt/interfaces/limelight/new_game/players/new_game.rb +5 -0
  45. data/lib/ttt/interfaces/limelight/new_game/players/player_type.rb +1 -0
  46. data/lib/ttt/interfaces/limelight/new_game/players/setup_button.rb +21 -0
  47. data/lib/ttt/interfaces/limelight/new_game/props.rb +21 -0
  48. data/lib/ttt/interfaces/limelight/new_game/styles.rb +23 -0
  49. data/lib/ttt/interfaces/limelight/partials/board_partial.rb +14 -0
  50. data/lib/ttt/interfaces/limelight/partials/menu_button_partial.rb +5 -0
  51. data/lib/ttt/interfaces/limelight/partials/move_history_partial.rb +6 -0
  52. data/lib/ttt/interfaces/limelight/partials/title_history_partial.rb +10 -0
  53. data/lib/ttt/interfaces/limelight/players/board.rb +3 -0
  54. data/lib/ttt/interfaces/limelight/players/game.rb +4 -0
  55. data/lib/ttt/interfaces/limelight/players/generic_move_history.rb +5 -0
  56. data/lib/ttt/interfaces/limelight/players/generic_player.rb +8 -0
  57. data/lib/ttt/interfaces/limelight/players/left_button.rb +3 -0
  58. data/lib/ttt/interfaces/limelight/players/main_menu.rb +3 -0
  59. data/lib/ttt/interfaces/limelight/players/right_button.rb +3 -0
  60. data/lib/ttt/interfaces/limelight/playscripts/game_playscript.rb +169 -0
  61. data/lib/ttt/interfaces/limelight/production.rb +14 -0
  62. data/lib/ttt/interfaces/limelight/spec/game_playscript_spec.rb +218 -0
  63. data/lib/ttt/interfaces/limelight/spec/main_menu/main_menu_spec.rb +38 -0
  64. data/lib/ttt/interfaces/limelight/spec/new_game/new_game_spec.rb +45 -0
  65. data/lib/ttt/interfaces/limelight/spec/spec_helper.rb +8 -0
  66. data/lib/ttt/interfaces/limelight/stages.rb +6 -0
  67. data/lib/ttt/interfaces/limelight/styles.rb +119 -0
  68. data/lib/ttt/interfaces/limelight/three_by_three/props.rb +1 -0
  69. data/lib/ttt/interfaces/limelight/three_by_three/styles.rb +39 -0
  70. data/lib/ttt/interfaces/limelight/three_by_three_by_three/props.rb +1 -0
  71. data/lib/ttt/interfaces/limelight/three_by_three_by_three/styles.rb +119 -0
  72. data/lib/ttt/interfaces/limelight/three_by_three_by_three_finished/props.rb +1 -0
  73. data/lib/ttt/interfaces/limelight/three_by_three_by_three_finished/styles.rb +119 -0
  74. data/lib/ttt/interfaces/limelight/three_by_three_finished/props.rb +1 -0
  75. data/lib/ttt/interfaces/limelight/three_by_three_finished/styles.rb +39 -0
  76. data/lib/ttt/interfaces/rails/app/controllers/application_controller.rb +3 -0
  77. data/lib/ttt/interfaces/rails/app/controllers/ttt_games_controller.rb +86 -0
  78. data/lib/ttt/interfaces/rails/app/helpers/application_helper.rb +2 -0
  79. data/lib/ttt/interfaces/rails/app/models/ttt_game.rb +34 -0
  80. data/lib/ttt/interfaces/rails/app/presenters/web_game_presenter.rb +159 -0
  81. data/lib/ttt/interfaces/rails/autotest/discover.rb +1 -0
  82. data/lib/ttt/interfaces/rails/config/application.rb +67 -0
  83. data/lib/ttt/interfaces/rails/config/boot.rb +6 -0
  84. data/lib/ttt/interfaces/rails/config/environment.rb +5 -0
  85. data/lib/ttt/interfaces/rails/config/environments/development.rb +37 -0
  86. data/lib/ttt/interfaces/rails/config/environments/production.rb +67 -0
  87. data/lib/ttt/interfaces/rails/config/environments/test.rb +37 -0
  88. data/lib/ttt/interfaces/rails/config/initializers/backtrace_silencers.rb +7 -0
  89. data/lib/ttt/interfaces/rails/config/initializers/inflections.rb +15 -0
  90. data/lib/ttt/interfaces/rails/config/initializers/mime_types.rb +5 -0
  91. data/lib/ttt/interfaces/rails/config/initializers/secret_token.rb +7 -0
  92. data/lib/ttt/interfaces/rails/config/initializers/session_store.rb +8 -0
  93. data/lib/ttt/interfaces/rails/config/initializers/wrap_parameters.rb +14 -0
  94. data/lib/ttt/interfaces/rails/config/routes.rb +49 -0
  95. data/lib/ttt/interfaces/rails/db/schema.rb +28 -0
  96. data/lib/ttt/interfaces/rails/db/seeds.rb +7 -0
  97. data/lib/ttt/interfaces/rails/spec/controllers/ttt_games_controller_spec.rb +211 -0
  98. data/lib/ttt/interfaces/rails/spec/models/ttt_game_spec.rb +76 -0
  99. data/lib/ttt/interfaces/rails/spec/presenters/web_game_presenter_spec.rb +52 -0
  100. data/lib/ttt/interfaces/rails/spec/spec_helper.rb +13 -0
  101. data/lib/ttt/interfaces/web_interface/html_generator.rb +76 -0
  102. data/lib/ttt/interfaces/web_interface/web_game_presenter.rb +0 -0
  103. data/lib/ttt/minimax.rb +46 -0
  104. data/lib/ttt/move_history.rb +10 -0
  105. data/lib/ttt/move_traverser.rb +49 -0
  106. data/lib/ttt/player.rb +15 -0
  107. data/lib/ttt/riak_db.rb +53 -0
  108. data/lib/ttt/setup.rb +59 -0
  109. data/lib/ttt/three_by_three.rb +35 -0
  110. data/lib/ttt/three_by_three_by_three.rb +37 -0
  111. data/spec/spec_helper.rb +22 -0
  112. data/spec/ttt/ai_easy_spec.rb +15 -0
  113. data/spec/ttt/ai_hard_spec.rb +76 -0
  114. data/spec/ttt/ai_medium_spec.rb +65 -0
  115. data/spec/ttt/ai_spec.rb +50 -0
  116. data/spec/ttt/board_spec.rb +96 -0
  117. data/spec/ttt/config_helper_spec.rb +54 -0
  118. data/spec/ttt/context_spec.rb +398 -0
  119. data/spec/ttt/four_by_four_spec.rb +112 -0
  120. data/spec/ttt/game_history_spec.rb +41 -0
  121. data/spec/ttt/game_interactor_spec.rb +197 -0
  122. data/spec/ttt/game_spec.rb +246 -0
  123. data/spec/ttt/human_spec.rb +18 -0
  124. data/spec/ttt/move_history_spec.rb +13 -0
  125. data/spec/ttt/move_traverser_spec.rb +75 -0
  126. data/spec/ttt/player_spec.rb +13 -0
  127. data/spec/ttt/riak_db_spec.rb +64 -0
  128. data/spec/ttt/setup_spec.rb +63 -0
  129. data/spec/ttt/three_by_three_by_three_spec.rb +130 -0
  130. data/spec/ttt/three_by_three_spec.rb +110 -0
  131. 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,13 @@
1
+ require 'spec_helper'
2
+
3
+ module TTT
4
+ describe Player do
5
+
6
+ describe "#initialize" do
7
+ it "should initialize a blank new player" do
8
+ player = Player.new(side: "x")
9
+ player.side.should == "x"
10
+ end
11
+ end
12
+ end
13
+ 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