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.
- checksums.yaml +4 -4
- data/bin/tic_tac_toe +3 -3
- data/coverage/.last_run.json +1 -1
- data/coverage/.resultset.json +135 -51
- data/lib/tic_tac_toe/board.rb +1 -1
- data/lib/tic_tac_toe/game.rb +23 -44
- data/lib/tic_tac_toe/game_factory.rb +51 -0
- data/lib/tic_tac_toe/player.rb +2 -2
- data/lib/tic_tac_toe/player_factory.rb +3 -3
- data/lib/tic_tac_toe/rules.rb +1 -1
- data/lib/tic_tac_toe/runner.rb +53 -0
- data/lib/tic_tac_toe/strategy/console_user.rb +1 -1
- data/lib/tic_tac_toe/strategy/minimax.rb +16 -18
- data/lib/tic_tac_toe/ui/console.rb +3 -3
- data/spec/integration/tictactoe/unbeatable_computer_spec.rb +3 -3
- data/spec/mocks/game.rb +1 -1
- data/spec/mocks/game_factory.rb +14 -0
- data/spec/mocks/player_factory.rb +2 -3
- data/spec/mocks/strategy/dynamic.rb +1 -1
- data/spec/tic_tac_toe/game_factory_spec.rb +78 -0
- data/spec/tic_tac_toe/game_spec.rb +78 -64
- data/spec/tic_tac_toe/player_factory_mock.rb +10 -0
- data/spec/tic_tac_toe/player_factory_spec.rb +9 -5
- data/spec/tic_tac_toe/player_spec.rb +16 -17
- data/spec/tic_tac_toe/runner_spec.rb +95 -0
- data/spec/tic_tac_toe/strategy/console_user_spec.rb +1 -1
- data/spec/tic_tac_toe/strategy/minimax_spec.rb +64 -65
- data/spec/tic_tac_toe/ui/console_spec.rb +1 -1
- data/tic_tac_toe_nhu.gemspec +1 -2
- metadata +8 -12
- data/lib/tic_tac_toe/game_state.rb +0 -35
- data/lib/tic_tac_toe/game_state_factory.rb +0 -56
- data/lib/tic_tac_toe/values.rb +0 -10
- data/spec/mocks/game_state.rb +0 -18
- data/spec/mocks/game_state_factory.rb +0 -14
- data/spec/mocks/player.rb +0 -16
- data/spec/tic_tac_toe/game_state_factory_spec.rb +0 -63
- data/spec/tic_tac_toe/game_state_spec.rb +0 -73
- data/spec/tic_tac_toe/values_spec.rb +0 -17
@@ -1,11 +1,10 @@
|
|
1
1
|
require 'surrogate/rspec'
|
2
|
-
require 'tic_tac_toe/values'
|
3
2
|
|
4
3
|
class MockPlayerFactory
|
5
4
|
Surrogate.endow(self)
|
6
5
|
|
7
|
-
define(:human) {|name = "
|
8
|
-
define(:computer) {|value =
|
6
|
+
define(:human) {|name = "Sue", value = "X"|}
|
7
|
+
define(:computer) {|board, value = "X", opponent="O"|}
|
9
8
|
end
|
10
9
|
|
11
10
|
describe TicTacToe::PlayerFactory do
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'tic_tac_toe/spec_helper'
|
2
|
+
require 'tic_tac_toe/game_factory'
|
3
|
+
require 'tic_tac_toe/player_factory'
|
4
|
+
require 'mocks/player_factory'
|
5
|
+
|
6
|
+
describe TicTacToe::GameFactory do
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
@board = "board"
|
10
|
+
@player_factory = MockPlayerFactory.new
|
11
|
+
@game_factory = TicTacToe::GameFactory.new(@player_factory)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "ensures MockPlayerFactory has the same interface as PlayerFactory" do
|
15
|
+
MockPlayerFactory.should be_substitutable_for(TicTacToe::PlayerFactory)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "returns 4 types of games" do
|
19
|
+
@game_factory.types.size.should == 4
|
20
|
+
end
|
21
|
+
|
22
|
+
it "sets the board in the game" do
|
23
|
+
game = @game_factory.create(1, @board)
|
24
|
+
game.board.should == @board
|
25
|
+
end
|
26
|
+
|
27
|
+
it "returns human vs computer game" do
|
28
|
+
human = "human"
|
29
|
+
computer = "computer"
|
30
|
+
@player_factory.will_have_human human
|
31
|
+
@player_factory.will_have_computer computer
|
32
|
+
|
33
|
+
game = @game_factory.create(1, @board)
|
34
|
+
game.current_player.should == human
|
35
|
+
|
36
|
+
@player_factory.was asked_for :computer
|
37
|
+
@player_factory.was asked_for :human
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns computer vs human game" do
|
41
|
+
human = "human"
|
42
|
+
computer = "computer"
|
43
|
+
@player_factory.will_have_human human
|
44
|
+
@player_factory.will_have_computer computer
|
45
|
+
|
46
|
+
game = @game_factory.create(2, @board)
|
47
|
+
game.current_player.should == computer
|
48
|
+
|
49
|
+
@player_factory.was asked_for :computer
|
50
|
+
@player_factory.was asked_for :human
|
51
|
+
end
|
52
|
+
|
53
|
+
it "returns user vs user game" do
|
54
|
+
human1 = "mary"
|
55
|
+
human2 = "alice"
|
56
|
+
@player_factory.will_have_human human1, human2
|
57
|
+
|
58
|
+
game = @game_factory.create(3, @board)
|
59
|
+
game.current_player.should == human1
|
60
|
+
|
61
|
+
@player_factory.was asked_for(:human).times(2)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "returns computer vs computer game" do
|
65
|
+
computer1 = "computer1"
|
66
|
+
computer2 = "computer2"
|
67
|
+
@player_factory.will_have_computer computer2, computer1
|
68
|
+
|
69
|
+
game = @game_factory.create(4, @board)
|
70
|
+
game.current_player.should == computer2
|
71
|
+
|
72
|
+
@player_factory.was asked_for(:computer).times(2)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "raises an error when the game type doesn't exist" do
|
76
|
+
lambda{@game_factory.create(5, @board)}.should raise_error(ArgumentError)
|
77
|
+
end
|
78
|
+
end
|
@@ -1,99 +1,113 @@
|
|
1
1
|
require 'tic_tac_toe/spec_helper'
|
2
2
|
require 'tic_tac_toe/game'
|
3
|
-
|
4
|
-
require '
|
5
|
-
require 'mocks/
|
6
|
-
require 'mocks/ui/console'
|
7
|
-
require 'mocks/player'
|
3
|
+
require 'tic_tac_toe/board'
|
4
|
+
require 'tic_tac_toe/player'
|
5
|
+
require 'mocks/strategy/dynamic'
|
8
6
|
|
9
7
|
describe TicTacToe::Game do
|
10
|
-
attr_reader :game, :ui, :game_state, :game_state_factory
|
11
|
-
|
12
8
|
before(:each) do
|
13
|
-
@
|
14
|
-
|
15
|
-
@
|
16
|
-
@
|
17
|
-
|
9
|
+
@board = TicTacToe::Board.new
|
10
|
+
|
11
|
+
@player1_strategy = MockDynamicStrategy.new
|
12
|
+
@player1 = TicTacToe::Player.new("Todd", "X", @player1_strategy)
|
13
|
+
|
14
|
+
@player2_strategy = MockDynamicStrategy.new
|
15
|
+
@player2 = TicTacToe::Player.new("John", "O", @player2_strategy)
|
18
16
|
|
19
|
-
|
20
|
-
game.start
|
21
|
-
ui.was told_to(:display_welcome_message)
|
17
|
+
@game = TicTacToe::Game.new(@board, @player1, @player2)
|
22
18
|
end
|
23
19
|
|
24
|
-
|
25
|
-
it "
|
26
|
-
|
27
|
-
@
|
20
|
+
context "marking board" do
|
21
|
+
it "mark the board with user input when caller doesn't pass in a move" do
|
22
|
+
@player1_strategy.add_move(1)
|
23
|
+
@game.make_move
|
24
|
+
@board.unique_marked_values.should include(@player1.value)
|
28
25
|
end
|
29
26
|
|
30
|
-
it "
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
@game_state_factory.was told_to(:create).with(game_type)
|
27
|
+
it "does not mark the board if user doesn't return an input and caller didn't pass in a move" do
|
28
|
+
@player1_strategy.add_move(nil)
|
29
|
+
@game.make_move
|
30
|
+
@board.unique_marked_values.should_not include(@player1.value)
|
35
31
|
end
|
36
32
|
|
37
|
-
it "
|
38
|
-
|
39
|
-
|
40
|
-
|
33
|
+
it "marks the board with the move passed in" do
|
34
|
+
@player1_strategy.add_move(1)
|
35
|
+
move = 2
|
36
|
+
@game.make_move(move)
|
37
|
+
@board.available_moves.should_not include(move)
|
41
38
|
end
|
42
|
-
end
|
43
|
-
|
44
|
-
describe "play game" do
|
45
|
-
attr_reader :player
|
46
39
|
|
47
|
-
|
48
|
-
@
|
49
|
-
|
50
|
-
|
40
|
+
it "marks the board with player move when move passed in is nil" do
|
41
|
+
@player1_strategy.add_move(1)
|
42
|
+
@game.make_move(nil)
|
43
|
+
@board.available_moves.should_not include(1)
|
51
44
|
end
|
52
45
|
|
53
|
-
it "
|
54
|
-
|
55
|
-
|
46
|
+
it "marks the board with current player value when the move passed in" do
|
47
|
+
move = 2
|
48
|
+
@game.make_move(move)
|
49
|
+
@board.unique_marked_values.should include(@player1.value)
|
56
50
|
end
|
51
|
+
end
|
57
52
|
|
58
|
-
|
59
|
-
|
60
|
-
|
53
|
+
describe "return winner player based on the value return from rules" do
|
54
|
+
it "is Todd when value is X" do
|
55
|
+
mark_board([0, 1, 2], @player1.value)
|
56
|
+
@game.winner.should == @player1
|
61
57
|
end
|
62
58
|
|
63
|
-
it "
|
64
|
-
|
65
|
-
|
59
|
+
it "is John when it is O" do
|
60
|
+
mark_board([0, 1, 2], @player2.value)
|
61
|
+
@game.winner.should == @player2
|
66
62
|
end
|
67
63
|
|
68
|
-
it "
|
69
|
-
|
70
|
-
game.start
|
71
|
-
player.was told_to(:move).times(2)
|
64
|
+
it "is nil when no one wins" do
|
65
|
+
@game.winner.should be_nil
|
72
66
|
end
|
67
|
+
end
|
73
68
|
|
74
|
-
|
75
|
-
|
76
|
-
|
69
|
+
describe "changes player" do
|
70
|
+
it "doesn't change player if player 1 doesn't return a move" do
|
71
|
+
@game.current_player.should == @player1
|
72
|
+
@player1_strategy.add_move(nil)
|
73
|
+
|
74
|
+
@game.make_move
|
75
|
+
@game.current_player.should == @player1
|
77
76
|
end
|
78
77
|
|
78
|
+
it "changes to player 2 after player 1 moves" do
|
79
|
+
@game.current_player.should == @player1
|
80
|
+
@player1_strategy.add_move(1)
|
81
|
+
|
82
|
+
@game.make_move
|
83
|
+
@game.current_player.should == @player2
|
84
|
+
end
|
79
85
|
end
|
80
86
|
|
81
|
-
describe "
|
82
|
-
it "
|
83
|
-
|
84
|
-
|
87
|
+
describe "game over" do
|
88
|
+
it "is over when there is a winner" do
|
89
|
+
mark_board([0, 1, 2], @player2.value)
|
90
|
+
@game.should be_over
|
91
|
+
end
|
92
|
+
|
93
|
+
it "is over when there is a tied" do
|
94
|
+
mark_board((0...9).to_a, "i")
|
95
|
+
@game.should be_over
|
96
|
+
end
|
97
|
+
|
98
|
+
it "is not over when there is no mark on the board" do
|
99
|
+
@game.should_not be_over
|
85
100
|
end
|
86
101
|
|
87
|
-
it "
|
88
|
-
|
89
|
-
|
90
|
-
game.start
|
91
|
-
ui.was told_to(:display_winner).with(winner)
|
102
|
+
it "is not over when there is no winner or a tied" do
|
103
|
+
mark_board([1, 2], @player1.value)
|
104
|
+
@game.should_not be_over
|
92
105
|
end
|
106
|
+
end
|
93
107
|
|
94
|
-
|
95
|
-
|
96
|
-
|
108
|
+
def mark_board(moves, value)
|
109
|
+
moves.each do |m|
|
110
|
+
@board.mark(m, value)
|
97
111
|
end
|
98
112
|
end
|
99
113
|
end
|
@@ -2,7 +2,6 @@ require 'tic_tac_toe/spec_helper'
|
|
2
2
|
require 'tic_tac_toe/player_factory'
|
3
3
|
require 'tic_tac_toe/strategy/minimax'
|
4
4
|
require 'tic_tac_toe/strategy/console_user'
|
5
|
-
require 'tic_tac_toe/values'
|
6
5
|
|
7
6
|
describe TicTacToe::PlayerFactory do
|
8
7
|
|
@@ -33,22 +32,27 @@ describe TicTacToe::PlayerFactory do
|
|
33
32
|
end
|
34
33
|
|
35
34
|
context "computer player" do
|
35
|
+
before(:each) do
|
36
|
+
@board = "fake board"
|
37
|
+
end
|
38
|
+
|
36
39
|
it "returns a computer player with given value" do
|
37
40
|
computer_value = "Danny"
|
38
|
-
|
41
|
+
opponent_value = "Bill"
|
42
|
+
player = @factory.computer(@board, computer_value, opponent_value)
|
39
43
|
player.value.should == computer_value
|
40
44
|
end
|
41
45
|
|
42
46
|
it "checks default strategy" do
|
43
|
-
@factory.computer.strategy.should be_kind_of(TicTacToe::Strategy::Minimax)
|
47
|
+
@factory.computer(@board).strategy.should be_kind_of(TicTacToe::Strategy::Minimax)
|
44
48
|
end
|
45
49
|
|
46
50
|
it "checks default name" do
|
47
|
-
@factory.computer.name.should == "Computer"
|
51
|
+
@factory.computer(@board).name.should == "Computer"
|
48
52
|
end
|
49
53
|
|
50
54
|
it "checks default value" do
|
51
|
-
@factory.computer.value.should == "O"
|
55
|
+
@factory.computer(@board).value.should == "O"
|
52
56
|
end
|
53
57
|
end
|
54
58
|
|
@@ -1,33 +1,32 @@
|
|
1
1
|
require 'tic_tac_toe/spec_helper'
|
2
2
|
require 'tic_tac_toe/player'
|
3
|
-
require 'tic_tac_toe/board'
|
4
|
-
require 'tic_tac_toe/values'
|
5
3
|
require 'mocks/strategy/dynamic'
|
6
4
|
|
7
5
|
describe TicTacToe::Player do
|
8
|
-
before(:each) do
|
9
|
-
@move = 4
|
10
|
-
@value = TicTacToe::VALUES[0]
|
11
|
-
@name = "blu"
|
12
|
-
@strategy = MockDynamicStrategy.new([@move])
|
13
|
-
@player = TicTacToe::Player.new(@name, @value, @strategy)
|
14
|
-
end
|
15
6
|
|
16
7
|
it "gets name" do
|
17
|
-
|
8
|
+
name = "bruce"
|
9
|
+
player = TicTacToe::Player.new(name, nil, nil)
|
10
|
+
player.name.should == name
|
18
11
|
end
|
19
12
|
|
20
13
|
it "gets player value" do
|
21
|
-
|
14
|
+
value = "X"
|
15
|
+
player = TicTacToe::Player.new(nil, value, nil)
|
16
|
+
player.value.should == value
|
22
17
|
end
|
23
18
|
|
24
|
-
it "gets
|
25
|
-
|
19
|
+
it "gets player's move" do
|
20
|
+
move = 4
|
21
|
+
strategy = MockDynamicStrategy.new([4])
|
22
|
+
player = TicTacToe::Player.new(nil, nil, strategy)
|
23
|
+
player.move.should == move
|
26
24
|
end
|
27
25
|
|
28
|
-
it "
|
29
|
-
|
30
|
-
|
31
|
-
|
26
|
+
it "gets strategy" do
|
27
|
+
strategy = MockDynamicStrategy.new([4])
|
28
|
+
player = TicTacToe::Player.new(nil, nil, strategy)
|
29
|
+
player.strategy.should == strategy
|
30
|
+
|
32
31
|
end
|
33
32
|
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'tic_tac_toe/spec_helper'
|
2
|
+
require 'tic_tac_toe/runner'
|
3
|
+
require 'tic_tac_toe/player'
|
4
|
+
require 'tic_tac_toe/game'
|
5
|
+
require 'tic_tac_toe/rules'
|
6
|
+
require 'tic_tac_toe/board'
|
7
|
+
require 'mocks/game'
|
8
|
+
require 'mocks/game_factory'
|
9
|
+
require 'mocks/ui/console'
|
10
|
+
require 'mocks/strategy/dynamic'
|
11
|
+
require 'mocks/rules'
|
12
|
+
|
13
|
+
describe TicTacToe::Runner do
|
14
|
+
before(:each) do
|
15
|
+
@ui = MockConsole.factory
|
16
|
+
@todd = TicTacToe::Player.new("Todd", "X", MockDynamicStrategy.new([1,2,3]))
|
17
|
+
@game = MockGame.factory current_player: @todd, winner: @todd
|
18
|
+
@game_factory = MockGameFactory.factory create: @game
|
19
|
+
@controller = TicTacToe::Runner.new(@ui, @game_factory)
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "starts game" do
|
23
|
+
it "displays welcome message" do
|
24
|
+
@controller.start
|
25
|
+
@ui.was told_to(:display_welcome_message)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "asked ui to get game type" do
|
29
|
+
@controller.start
|
30
|
+
@ui.was asked_for(:game_type)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "creates a game based on user input" do
|
34
|
+
@controller.start
|
35
|
+
@game_factory.was told_to(:create)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "asks ui for game type again if the input is incorrect" do
|
39
|
+
@game_factory.will_create ArgumentError.new, @game
|
40
|
+
@controller.start
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "play game" do
|
45
|
+
before(:each) do
|
46
|
+
@game.will_over? false, true
|
47
|
+
end
|
48
|
+
|
49
|
+
it "display board" do
|
50
|
+
@controller.start
|
51
|
+
@ui.was told_to(:display_board)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "displays whose turn it is" do
|
55
|
+
@controller.start
|
56
|
+
@ui.was told_to(:display_player_turn).with(@todd)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "tells game to make a move" do
|
60
|
+
@game.will_over? false, true
|
61
|
+
@controller.start
|
62
|
+
@game.was told_to(:make_move)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "asks for game move until game is over" do
|
66
|
+
@game.will_over? false, false, false, true
|
67
|
+
@controller.start
|
68
|
+
@game.was told_to(:make_move).times(3)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "displays message when square is not available" do
|
72
|
+
@game.will_make_move TicTacToe::MoveNotAvailableError.new
|
73
|
+
@controller.start
|
74
|
+
@ui.was told_to(:display_square_not_available)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "end game" do
|
79
|
+
it "displays the board when the game is over" do
|
80
|
+
@controller.start
|
81
|
+
@ui.was told_to(:display_board)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "notifies user when player wins" do
|
85
|
+
@controller.start
|
86
|
+
@ui.was told_to(:display_winner).with(@todd)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "notifies user when it's a tied game" do
|
90
|
+
@game.will_have_winner nil
|
91
|
+
@controller.start
|
92
|
+
@ui.was told_to(:display_tied_game)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -13,7 +13,7 @@ describe TicTacToe::Strategy::ConsoleUser do
|
|
13
13
|
it "prompts the user for a move" do
|
14
14
|
@output.should_receive(:puts).with("Please enter a square number that is not marked: ")
|
15
15
|
@input.should_receive(:gets).and_return("3")
|
16
|
-
@strategy.move
|
16
|
+
@strategy.move
|
17
17
|
end
|
18
18
|
|
19
19
|
it "returns a number when user enters a number" do
|