tic_tac_toe_nhu 0.0.5 → 0.0.11

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/bin/tic_tac_toe +3 -3
  3. data/coverage/.last_run.json +1 -1
  4. data/coverage/.resultset.json +135 -51
  5. data/lib/tic_tac_toe/board.rb +1 -1
  6. data/lib/tic_tac_toe/game.rb +23 -44
  7. data/lib/tic_tac_toe/game_factory.rb +51 -0
  8. data/lib/tic_tac_toe/player.rb +2 -2
  9. data/lib/tic_tac_toe/player_factory.rb +3 -3
  10. data/lib/tic_tac_toe/rules.rb +1 -1
  11. data/lib/tic_tac_toe/runner.rb +53 -0
  12. data/lib/tic_tac_toe/strategy/console_user.rb +1 -1
  13. data/lib/tic_tac_toe/strategy/minimax.rb +16 -18
  14. data/lib/tic_tac_toe/ui/console.rb +3 -3
  15. data/spec/integration/tictactoe/unbeatable_computer_spec.rb +3 -3
  16. data/spec/mocks/game.rb +1 -1
  17. data/spec/mocks/game_factory.rb +14 -0
  18. data/spec/mocks/player_factory.rb +2 -3
  19. data/spec/mocks/strategy/dynamic.rb +1 -1
  20. data/spec/tic_tac_toe/game_factory_spec.rb +78 -0
  21. data/spec/tic_tac_toe/game_spec.rb +78 -64
  22. data/spec/tic_tac_toe/player_factory_mock.rb +10 -0
  23. data/spec/tic_tac_toe/player_factory_spec.rb +9 -5
  24. data/spec/tic_tac_toe/player_spec.rb +16 -17
  25. data/spec/tic_tac_toe/runner_spec.rb +95 -0
  26. data/spec/tic_tac_toe/strategy/console_user_spec.rb +1 -1
  27. data/spec/tic_tac_toe/strategy/minimax_spec.rb +64 -65
  28. data/spec/tic_tac_toe/ui/console_spec.rb +1 -1
  29. data/tic_tac_toe_nhu.gemspec +1 -2
  30. metadata +8 -12
  31. data/lib/tic_tac_toe/game_state.rb +0 -35
  32. data/lib/tic_tac_toe/game_state_factory.rb +0 -56
  33. data/lib/tic_tac_toe/values.rb +0 -10
  34. data/spec/mocks/game_state.rb +0 -18
  35. data/spec/mocks/game_state_factory.rb +0 -14
  36. data/spec/mocks/player.rb +0 -16
  37. data/spec/tic_tac_toe/game_state_factory_spec.rb +0 -63
  38. data/spec/tic_tac_toe/game_state_spec.rb +0 -73
  39. data/spec/tic_tac_toe/values_spec.rb +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8f1770dfd1f3fd4f446e2d8ccb4d31e023ef4986
4
- data.tar.gz: d3d62e4b846be464fcf0343e7d3decc94c6afeca
3
+ metadata.gz: 47abe0e371c9ceb90b20c8aab57c555578eb85d2
4
+ data.tar.gz: 83d834d4f04337e278a19bea6114e582ade53a38
5
5
  SHA512:
6
- metadata.gz: ad5258407ba0594a5988b1bbdb9a25ba0341da84746d61444ef0e906d913e98775ff3f7c20092e675d96ee86ba9b98fc938ce149c1d26ee2443959ef4532d667
7
- data.tar.gz: 90f0131d85e62ef241ca81aafb2e65d50288e80b2f7765c6124a7b7c4cee7e6a0eabfdd50f509433c7786b3e3a0b123fe8d339071cead8e343dfc8606810e519
6
+ metadata.gz: 42ec301ab22138675081262882b8f95ba77a77dd4be6a62b0f65475288d63a5f8982993adc0c1f7e914afe114cac08922776e38c8f92e5d455b3f0c116eeb290
7
+ data.tar.gz: fa35df90dabda57091a2eae86e637c05334c953af8430cc47bda707e33c2e54297ddf11c2163729eea1ba2ed8af8f90178f94c69ee8c7c74acb82454d86bae99
data/bin/tic_tac_toe CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  $LOAD_PATH << File.expand_path('../../lib', __FILE__)
3
- require 'tic_tac_toe/game'
3
+ require 'tic_tac_toe/runner'
4
4
 
5
- game = TicTacToe::Game.new
6
- game.start
5
+ runner = TicTacToe::Runner.new
6
+ runner.start
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "result": {
3
- "covered_percent": 91.14
3
+ "covered_percent": 100.0
4
4
  }
5
5
  }
@@ -1,149 +1,233 @@
1
1
  {
2
2
  "RSpec": {
3
3
  "coverage": {
4
- "/Users/nhunguyen/Documents/Ruby/tictactoe/lib/tic_tac_toe/rules.rb": [
4
+ "/Users/nhunguyen/Documents/Ruby/tictactoe/lib/tic_tac_toe/game_factory.rb": [
5
5
  1,
6
6
  1,
7
7
  1,
8
- 30,
8
+ null,
9
+ 1,
10
+ 1,
11
+ 1,
12
+ 13,
9
13
  null,
10
14
  null,
11
15
  1,
12
- 8,
13
- 3,
14
- 3,
16
+ 6,
15
17
  null,
16
18
  null,
17
19
  1,
18
- 4,
20
+ 6,
19
21
  null,
22
+ 2,
20
23
  null,
21
24
  1,
22
- 77,
23
25
  null,
26
+ 1,
24
27
  null,
25
28
  1,
29
+ null,
26
30
  1,
27
- 47,
28
- 734,
29
31
  null,
30
32
  null,
31
33
  null,
32
34
  1,
33
- 47,
35
+ 1,
36
+ 1,
37
+ null,
38
+ null,
39
+ 1,
40
+ 2,
41
+ null,
42
+ null,
43
+ 1,
44
+ 1,
45
+ null,
46
+ null,
47
+ 1,
48
+ 1,
49
+ null,
50
+ null,
51
+ 1,
52
+ 5,
34
53
  null,
35
54
  null,
36
55
  null
37
56
  ],
38
- "/Users/nhunguyen/Documents/Ruby/tictactoe/lib/tic_tac_toe/board.rb": [
57
+ "/Users/nhunguyen/Documents/Ruby/tictactoe/lib/tic_tac_toe/game.rb": [
58
+ 1,
59
+ null,
39
60
  1,
40
61
  1,
62
+ 1,
63
+ null,
64
+ 1,
65
+ 19,
66
+ 19,
67
+ 19,
68
+ 19,
41
69
  null,
42
70
  null,
43
71
  1,
72
+ 7,
73
+ 7,
74
+ 5,
75
+ 5,
76
+ null,
77
+ null,
78
+ null,
44
79
  1,
80
+ 4,
81
+ null,
45
82
  null,
46
83
  1,
47
- 30,
48
- 30,
84
+ 3,
49
85
  null,
50
86
  null,
51
87
  1,
52
- 30,
53
- 30,
54
- 30,
88
+ 1,
89
+ 5,
55
90
  null,
56
91
  null,
57
92
  1,
58
- 107,
59
- 107,
60
- 107,
93
+ 3,
94
+ 2,
61
95
  null,
62
- 0,
63
96
  null,
64
97
  null,
98
+ null
99
+ ],
100
+ "/Users/nhunguyen/Documents/Ruby/tictactoe/lib/tic_tac_toe/runner.rb": [
101
+ 1,
102
+ 1,
103
+ 1,
65
104
  null,
66
105
  1,
67
- 0,
106
+ 1,
107
+ 1,
108
+ 1,
109
+ 12,
110
+ 12,
111
+ 12,
68
112
  null,
69
113
  null,
70
114
  1,
71
- 5,
115
+ 12,
116
+ 12,
117
+ 12,
118
+ 12,
119
+ 12,
120
+ null,
121
+ null,
122
+ 1,
123
+ 1,
124
+ 13,
125
+ 13,
126
+ 13,
127
+ 1,
128
+ 1,
129
+ null,
72
130
  null,
73
131
  null,
74
132
  1,
75
- 0,
133
+ 7,
134
+ 7,
135
+ 7,
136
+ 7,
137
+ 7,
138
+ 1,
139
+ 1,
140
+ null,
76
141
  null,
77
142
  null,
78
143
  1,
79
- 47,
80
- 141,
144
+ 12,
145
+ 12,
146
+ 11,
81
147
  null,
148
+ 1,
149
+ null,
150
+ null,
151
+ null,
152
+ null,
153
+ null
154
+ ],
155
+ "/Users/nhunguyen/Documents/Ruby/tictactoe/lib/tic_tac_toe/ui/console.rb": [
156
+ 1,
82
157
  null,
158
+ 1,
159
+ 1,
83
160
  null,
84
161
  1,
85
- 47,
86
- 47,
162
+ 14,
163
+ 14,
87
164
  null,
88
- 1269,
89
- 141,
90
165
  null,
91
- 47,
166
+ 1,
167
+ 1,
92
168
  null,
93
169
  null,
94
170
  1,
95
- 47,
96
- 47,
97
- 47,
171
+ 4,
98
172
  null,
99
173
  null,
100
174
  1,
101
175
  5,
102
176
  5,
103
- 45,
104
- null,
105
177
  5,
106
- null,
178
+ 5,
179
+ 4,
107
180
  null,
108
181
  1,
109
- 0,
110
- 0,
111
- 0,
112
182
  null,
113
- 0,
114
183
  null,
115
184
  null,
116
185
  1,
117
186
  1,
118
- 152,
119
- 152,
120
187
  null,
121
- 134,
188
+ null,
189
+ 1,
190
+ 1,
191
+ null,
192
+ null,
193
+ 1,
194
+ 1,
122
195
  null,
123
196
  null,
124
197
  1,
125
- 152,
126
- 152,
198
+ 1,
127
199
  null,
128
200
  null,
129
201
  1,
130
- 152,
202
+ 1,
203
+ 4,
204
+ 4,
205
+ 21,
206
+ 21,
207
+ null,
208
+ 4,
131
209
  null,
132
210
  null,
133
211
  1,
134
- 47,
135
- 423,
212
+ 5,
213
+ 5,
214
+ 20,
215
+ null,
216
+ 5,
217
+ null,
136
218
  null,
137
- 47,
219
+ 1,
220
+ 20,
138
221
  null,
139
222
  null,
140
223
  1,
141
- 470,
224
+ 40,
225
+ 20,
142
226
  null,
143
227
  null,
144
228
  null
145
229
  ]
146
230
  },
147
- "timestamp": 1375217786
231
+ "timestamp": 1375736808
148
232
  }
149
233
  }
@@ -47,7 +47,7 @@ module TicTacToe
47
47
  result = []
48
48
  (0...size).each do |col|
49
49
  result << squares.values_at(* squares.each_index.select do |i|
50
- (col - i) % 3 == 0
50
+ (col - i) % size == 0
51
51
  end)
52
52
  end
53
53
  result
@@ -1,62 +1,41 @@
1
- require 'tic_tac_toe/ui/console'
2
- require 'tic_tac_toe/game_state_factory'
3
- require 'tic_tac_toe/board'
1
+ require 'tic_tac_toe/rules'
4
2
 
5
3
  module TicTacToe
6
4
  class Game
5
+ attr_reader :current_player, :board
7
6
 
8
- def initialize(ui = TicTacToe::Console.new, game_state_factory = TicTacToe::GameStateFactory.new)
9
- @ui = ui
10
- @game_state_factory = game_state_factory
7
+ def initialize(board, player1, player2)
8
+ @board = board
9
+ @current_player = @player1 = player1
10
+ @player2 = player2
11
+ @rules = TicTacToe::Rules.new(@board)
11
12
  end
12
13
 
13
- def start
14
- ui.display_welcome_message
15
- @game_state = create_game_state
16
- play until game_state.game_over?
17
- ui.display_board(board)
18
- display_result
19
- end
20
-
21
- private
22
- attr_reader :ui, :game_state, :game_state_factory
23
-
24
- def create_game_state
25
- game_type = ui.game_type
26
- begin
27
- game_state_factory.create(game_type)
28
- rescue ArgumentError
29
- create_game_state
14
+ def make_move(*move) #rename to make player move
15
+ player_move = move[0] || @current_player.move
16
+ if player_move
17
+ @board.mark(player_move, @current_player.value)
18
+ change_player
30
19
  end
31
20
  end
32
21
 
33
- def play
34
- ui.display_board(board)
35
- player = game_state.current_player
36
- ui.display_player_turn(player)
37
- make_move(player)
38
- game_state.change_player
22
+ def over?
23
+ @rules.game_over?
39
24
  end
40
25
 
41
- def make_move(player)
42
- begin
43
- player.move(board)
44
- rescue MoveNotAvailableError
45
- make_move(player)
46
- end
26
+ def winner
27
+ player(@rules.winner)
47
28
  end
48
29
 
49
- def display_result
50
- winner = game_state.winner
51
- if winner
52
- ui.display_winner(winner)
53
- else
54
- ui.display_tied_game
55
- end
30
+ private
31
+ def change_player
32
+ @current_player = (@current_player == @player1) ? @player2 : @player1
56
33
  end
57
34
 
58
- def board
59
- game_state.board
35
+ def player(mark)
36
+ return @player1 if mark == @player1.value
37
+ return @player2 if mark == @player2.value
60
38
  end
39
+
61
40
  end
62
41
  end
@@ -0,0 +1,51 @@
1
+ require 'tic_tac_toe/game'
2
+ require 'tic_tac_toe/board'
3
+ require 'tic_tac_toe/player_factory'
4
+
5
+ module TicTacToe
6
+ class GameFactory
7
+ def initialize(player_factory = TicTacToe::PlayerFactory.new)
8
+ @player_factory = player_factory
9
+ end
10
+
11
+ def types
12
+ [[:human, :computer], [:computer, :human], [:human, :human], [:computer, :computer]]
13
+ end
14
+
15
+ def create(type_index, board)
16
+ case type_index
17
+ when 1
18
+ human_computer_game(board)
19
+ when 2
20
+ computer_human_game(board)
21
+ when 3
22
+ human_human_game(board)
23
+ when 4
24
+ computer_computer_game(board)
25
+ else
26
+ raise ArgumentError, "Type does not exist. Please select a number corresponding to the game type."
27
+ end
28
+ end
29
+
30
+ private
31
+ def computer_human_game(board)
32
+ create_game(board, @player_factory.computer(board), @player_factory.human)
33
+ end
34
+
35
+ def human_computer_game(board)
36
+ create_game(board, @player_factory.human, @player_factory.computer(board))
37
+ end
38
+
39
+ def human_human_game(board)
40
+ create_game(board, @player_factory.human, @player_factory.human("Friend", "O"))
41
+ end
42
+
43
+ def computer_computer_game(board)
44
+ create_game(board, @player_factory.computer(board, "X", "O"), @player_factory.computer(board, "O", "X"))
45
+ end
46
+
47
+ def create_game(board, player1, player2)
48
+ TicTacToe::Game.new(board, player1, player2)
49
+ end
50
+ end
51
+ end
@@ -8,8 +8,8 @@ module TicTacToe
8
8
  @strategy = strategy
9
9
  end
10
10
 
11
- def move(board)
12
- board.mark(strategy.move(board), value)
11
+ def move
12
+ @strategy.move
13
13
  end
14
14
  end
15
15
  end
@@ -5,12 +5,12 @@ require 'tic_tac_toe/player'
5
5
  module TicTacToe
6
6
  class PlayerFactory
7
7
 
8
- def human(name = "User", value = TicTacToe::VALUES[0])
8
+ def human(name = "User", value = "X")
9
9
  TicTacToe::Player.new(name, value, TicTacToe::Strategy::ConsoleUser.new)
10
10
  end
11
11
 
12
- def computer(value = TicTacToe::VALUES[1])
13
- ai = TicTacToe::Strategy::Minimax.new(value)
12
+ def computer(board, value = "O", opponent_value = "X")
13
+ ai = TicTacToe::Strategy::Minimax.new(board, value, opponent_value)
14
14
  TicTacToe::Player.new("Computer", value, ai)
15
15
  end
16
16
  end
@@ -29,4 +29,4 @@ module TicTacToe
29
29
  @board.rows + @board.columns + @board.diagonals
30
30
  end
31
31
  end
32
- end
32
+ end
@@ -0,0 +1,53 @@
1
+ require 'tic_tac_toe/ui/console'
2
+ require 'tic_tac_toe/game_factory'
3
+ require 'tic_tac_toe/board'
4
+
5
+ module TicTacToe
6
+ class Runner
7
+ attr_reader :board
8
+ def initialize(ui = TicTacToe::Console.new, game_factory = TicTacToe::GameFactory.new)
9
+ @ui = ui
10
+ @board = TicTacToe::Board.new
11
+ @game_factory = game_factory
12
+ end
13
+
14
+ def start
15
+ @ui.display_welcome_message
16
+ @game = create_game
17
+ play until @game.over?
18
+ @ui.display_board(@board)
19
+ display_result
20
+ end
21
+
22
+ private
23
+ def create_game
24
+ game_type = @ui.game_type
25
+ begin
26
+ @game_factory.create(game_type, @board)
27
+ rescue ArgumentError
28
+ create_game
29
+ end
30
+ end
31
+
32
+ def play
33
+ @ui.display_board(@board)
34
+ player = @game.current_player
35
+ @ui.display_player_turn(player)
36
+ begin
37
+ @game.make_move
38
+ rescue MoveNotAvailableError
39
+ @ui.display_square_not_available
40
+ end
41
+ end
42
+
43
+ def display_result
44
+ winner = @game.winner
45
+ if winner
46
+ @ui.display_winner(winner)
47
+ else
48
+ @ui.display_tied_game
49
+ end
50
+ end
51
+
52
+ end
53
+ end
@@ -7,7 +7,7 @@ module TicTacToe
7
7
  @output = output
8
8
  end
9
9
 
10
- def move(*board)
10
+ def move
11
11
  move = nil
12
12
 
13
13
  until move =~ NUMBER
@@ -1,35 +1,33 @@
1
1
  require 'tic_tac_toe/rules'
2
- require 'tic_tac_toe/values'
3
2
 
4
3
  module TicTacToe
5
4
  module Strategy
6
5
  class Minimax
7
- WINNING_SCORE = 1
8
- LOSING_SCORE = -1
9
- TIE = 0
10
- MIDDLE_SQUARE = 4
11
-
12
- def initialize(player_value)
13
- @player_value = player_value
14
- @opponent_value = TicTacToe::Values.opponent(@player_value)
6
+ def initialize(board, player, opponent)
7
+ @board = board
8
+ @player = player
9
+ @opponent = opponent
15
10
  end
16
11
 
17
- def move(board)
18
- return first_move(board) if first_move?(board)
19
- move = minimax(player_value, board)
12
+ def move
13
+ return first_move if first_move?
14
+ move = minimax(@player, @board)
20
15
  move.move
21
16
  end
22
17
 
23
18
  private
24
- attr_reader :player_value, :opponent_value
19
+ WINNING_SCORE = 1
20
+ LOSING_SCORE = -1
21
+ TIE = 0
22
+ MIDDLE_SQUARE = 4
25
23
 
26
- def first_move?(board)
27
- moves_count = board.number_of_moves
24
+ def first_move?
25
+ moves_count = @board.number_of_moves
28
26
  moves_count == 0 || moves_count == 1
29
27
  end
30
28
 
31
- def first_move(board)
32
- return MIDDLE_SQUARE if board.available_moves.include?(MIDDLE_SQUARE)
29
+ def first_move
30
+ return MIDDLE_SQUARE if @board.available_moves.include?(MIDDLE_SQUARE)
33
31
  0
34
32
  end
35
33
 
@@ -65,7 +63,7 @@ module TicTacToe
65
63
  end
66
64
 
67
65
  def opponent(player)
68
- (player == player_value) ? opponent_value : player_value
66
+ (player == @player) ? @opponent : @player
69
67
  end
70
68
 
71
69
  def best_move(moves)
@@ -1,4 +1,4 @@
1
- require 'tic_tac_toe/game_state_factory'
1
+ require 'tic_tac_toe/game_factory'
2
2
 
3
3
  module TicTacToe
4
4
  class Console
@@ -28,7 +28,7 @@ module TicTacToe
28
28
  end
29
29
 
30
30
  def display_winner(winner)
31
- @output.puts("#{winner.name}(#{winner.value}) wins!")
31
+ @output.puts("#{winner.name}(#{winner.value}) win!")
32
32
  end
33
33
 
34
34
  def display_tied_game
@@ -55,7 +55,7 @@ module TicTacToe
55
55
 
56
56
  def game_type_list
57
57
  result = ""
58
- TicTacToe::GameStateFactory.new.types.each_with_index.map do |value, index|
58
+ TicTacToe::GameFactory.new.types.each_with_index do |value, index|
59
59
  result << "#{index + 1} - #{game_type_values(value)}\n"
60
60
  end
61
61
  result
@@ -26,8 +26,8 @@ describe "Unbeatable computer", :slow_test => true do
26
26
  end
27
27
 
28
28
  def make_computer_move(clone_board)
29
- computer = TicTacToe::PlayerFactory.new.computer
30
- computer.move(clone_board)
29
+ computer = TicTacToe::PlayerFactory.new.computer(clone_board)
30
+ clone_board.mark(computer.move, computer.value)
31
31
  clone_board
32
32
  end
33
33
 
@@ -50,7 +50,7 @@ describe "Unbeatable computer", :slow_test => true do
50
50
 
51
51
  def make_players_move(board, move_history, move)
52
52
  move_history << move
53
- board.mark(move, @human_value)
53
+ board.mark(move, "X")
54
54
  make_computer_move(board) if !rules(board).game_over?
55
55
  play_game_for_each_available_move(board, move_history)
56
56
  end
data/spec/mocks/game.rb CHANGED
@@ -5,7 +5,7 @@ class MockGame
5
5
  define_reader :board
6
6
  define_reader :current_player
7
7
 
8
- define :make_move
8
+ define(:make_move) {|*value| }
9
9
  define :winner
10
10
  define(:over?){true}
11
11
  end
@@ -0,0 +1,14 @@
1
+ require 'surrogate/rspec'
2
+
3
+ class MockGameFactory
4
+ Surrogate.endow(self)
5
+ define(:initialize) {|player_factory|}
6
+ define :types
7
+ define(:create) {|type, board|}
8
+ end
9
+
10
+ describe TicTacToe::GameFactory do
11
+ it "checks game factory" do
12
+ MockGameFactory.should be_substitutable_for(TicTacToe::GameFactory)
13
+ end
14
+ end