tic_tac_toe_nhu 0.0.4 → 0.0.5
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 +2 -2
- data/coverage/.last_run.json +1 -1
- data/coverage/.resultset.json +51 -136
- data/lib/tic_tac_toe/game.rb +44 -23
- data/lib/tic_tac_toe/game_state.rb +35 -0
- data/lib/tic_tac_toe/game_state_factory.rb +56 -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/strategy/console_user.rb +1 -1
- data/lib/tic_tac_toe/strategy/minimax.rb +18 -16
- data/lib/tic_tac_toe/ui/console.rb +3 -3
- data/lib/tic_tac_toe/values.rb +10 -0
- data/spec/integration/tictactoe/unbeatable_computer_spec.rb +3 -3
- data/spec/mocks/game_state.rb +18 -0
- data/spec/mocks/game_state_factory.rb +14 -0
- data/spec/mocks/player.rb +16 -0
- data/spec/mocks/player_factory.rb +3 -2
- data/spec/mocks/strategy/dynamic.rb +1 -1
- data/spec/tic_tac_toe/game_spec.rb +66 -61
- data/spec/tic_tac_toe/game_state_factory_spec.rb +63 -0
- data/spec/tic_tac_toe/game_state_spec.rb +73 -0
- data/spec/tic_tac_toe/player_factory_spec.rb +5 -9
- data/spec/tic_tac_toe/player_spec.rb +17 -16
- data/spec/tic_tac_toe/strategy/console_user_spec.rb +1 -1
- data/spec/tic_tac_toe/strategy/minimax_spec.rb +65 -64
- data/spec/tic_tac_toe/ui/console_spec.rb +1 -1
- data/spec/tic_tac_toe/values_spec.rb +17 -0
- data/tic_tac_toe_nhu.gemspec +1 -1
- metadata +10 -8
- data/lib/tic_tac_toe/game_factory.rb +0 -51
- data/lib/tic_tac_toe/main.rb +0 -54
- data/spec/integration/tictactoe/tic_tac_toe.rb +0 -4
- data/spec/mocks/game_factory.rb +0 -14
- data/spec/tic_tac_toe/game_factory_spec.rb +0 -78
- data/spec/tic_tac_toe/main_spec.rb +0 -95
- data/spec/tic_tac_toe/player_factory_mock.rb +0 -10
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'surrogate/rspec'
|
2
|
+
|
3
|
+
class MockPlayer
|
4
|
+
Surrogate.endow(self)
|
5
|
+
define(:initialize) {|name = "Player", value = "X", strategy = "no"|}
|
6
|
+
define_reader :name
|
7
|
+
define_reader :value
|
8
|
+
define_reader :strategy
|
9
|
+
define(:move) {|board|}
|
10
|
+
end
|
11
|
+
|
12
|
+
describe TicTacToe::Player do
|
13
|
+
it "checks if mock is substitutable" do
|
14
|
+
MockPlayer.should be_substitutable_for(TicTacToe::Player)
|
15
|
+
end
|
16
|
+
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
require 'surrogate/rspec'
|
2
|
+
require 'tic_tac_toe/values'
|
2
3
|
|
3
4
|
class MockPlayerFactory
|
4
5
|
Surrogate.endow(self)
|
5
6
|
|
6
|
-
define(:human) {|name = "
|
7
|
-
define(:computer) {|
|
7
|
+
define(:human) {|name = "human", value = TicTacToe::VALUES[0]|}
|
8
|
+
define(:computer) {|value = TicTacToe::VALUES[1]|}
|
8
9
|
end
|
9
10
|
|
10
11
|
describe TicTacToe::PlayerFactory do
|
@@ -1,94 +1,99 @@
|
|
1
1
|
require 'tic_tac_toe/spec_helper'
|
2
2
|
require 'tic_tac_toe/game'
|
3
|
-
require 'tic_tac_toe/board'
|
4
|
-
require 'tic_tac_toe/player'
|
5
|
-
require 'mocks/strategy/dynamic'
|
6
3
|
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
require 'mocks/game_state_factory'
|
5
|
+
require 'mocks/game_state'
|
6
|
+
require 'mocks/ui/console'
|
7
|
+
require 'mocks/player'
|
10
8
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
@player2_strategy = MockDynamicStrategy.new
|
15
|
-
@player2 = TicTacToe::Player.new("John", "O", @player2_strategy)
|
9
|
+
describe TicTacToe::Game do
|
10
|
+
attr_reader :game, :ui, :game_state, :game_state_factory
|
16
11
|
|
17
|
-
|
12
|
+
before(:each) do
|
13
|
+
@game_state = MockGameState.factory
|
14
|
+
@game_state_factory = MockGameStateFactory.factory create: game_state
|
15
|
+
@ui = MockConsole.factory
|
16
|
+
@game = TicTacToe::Game.new(@ui, @game_state_factory)
|
18
17
|
end
|
19
18
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
@game.make_move
|
24
|
-
@board.unique_marked_values.should include(@player1.value)
|
25
|
-
end
|
26
|
-
|
27
|
-
it "does not mark the board if user doesn't return an input" do
|
28
|
-
@player1_strategy.add_move(nil)
|
29
|
-
@game.make_move
|
30
|
-
@board.unique_marked_values.should_not include(@player1.value)
|
31
|
-
end
|
19
|
+
it "displays a welcome message" do
|
20
|
+
game.start
|
21
|
+
ui.was told_to(:display_welcome_message)
|
32
22
|
end
|
33
23
|
|
34
|
-
describe "
|
35
|
-
it "
|
36
|
-
|
37
|
-
@
|
24
|
+
describe "create game state" do
|
25
|
+
it "asks user for a game type" do
|
26
|
+
game.start
|
27
|
+
@ui.was asked_for(:game_type)
|
38
28
|
end
|
39
29
|
|
40
|
-
it "
|
41
|
-
|
42
|
-
|
30
|
+
it "asks game state factory to create a game with input game type" do
|
31
|
+
game_type = 4
|
32
|
+
ui.will_have_game_type 4
|
33
|
+
game.start
|
34
|
+
@game_state_factory.was told_to(:create).with(game_type)
|
43
35
|
end
|
44
36
|
|
45
|
-
it "
|
46
|
-
|
37
|
+
it "asks ui for game type again if the input is incorrect" do
|
38
|
+
game_state_factory.will_create ArgumentError.new, game_state
|
39
|
+
game.start
|
40
|
+
ui.was asked_for(:game_type).times(2)
|
47
41
|
end
|
48
42
|
end
|
49
43
|
|
50
|
-
describe "
|
51
|
-
|
52
|
-
@game.current_player.should == @player1
|
53
|
-
@player1_strategy.add_move(nil)
|
44
|
+
describe "play game" do
|
45
|
+
attr_reader :player
|
54
46
|
|
55
|
-
|
56
|
-
@
|
47
|
+
before(:each) do
|
48
|
+
@player = MockPlayer.new
|
49
|
+
game_state.will_game_over? false, true
|
50
|
+
game_state.will_have_current_player @player
|
57
51
|
end
|
58
52
|
|
59
|
-
it "
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
@game.make_move
|
64
|
-
@game.current_player.should == @player2
|
53
|
+
it "displays the board" do
|
54
|
+
game.start
|
55
|
+
ui.was told_to(:display_board)
|
65
56
|
end
|
66
|
-
end
|
67
57
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
@game.should be_over
|
58
|
+
it "tells ui to display player turn" do
|
59
|
+
game.start
|
60
|
+
ui.was told_to(:display_player_turn).with(player)
|
72
61
|
end
|
73
62
|
|
74
|
-
it "
|
75
|
-
|
76
|
-
|
63
|
+
it "told player to move" do
|
64
|
+
game.start
|
65
|
+
player.was told_to(:move)
|
77
66
|
end
|
78
67
|
|
79
|
-
it "
|
80
|
-
|
68
|
+
it "tells player to move again if there is an error" do
|
69
|
+
player.will_move TicTacToe::MoveNotAvailableError.new, nil
|
70
|
+
game.start
|
71
|
+
player.was told_to(:move).times(2)
|
81
72
|
end
|
82
73
|
|
83
|
-
it "
|
84
|
-
|
85
|
-
|
74
|
+
it "changes the player after a player move" do
|
75
|
+
game.start
|
76
|
+
game_state.was told_to(:change_player)
|
86
77
|
end
|
78
|
+
|
87
79
|
end
|
88
80
|
|
89
|
-
|
90
|
-
|
91
|
-
|
81
|
+
describe "end game" do
|
82
|
+
it "display a board at the end of the game" do
|
83
|
+
game.start
|
84
|
+
ui.was told_to(:display_board)
|
85
|
+
end
|
86
|
+
|
87
|
+
it "asks ui to display a winner if there is a winner" do
|
88
|
+
winner = "Winner"
|
89
|
+
game_state.will_have_winner winner
|
90
|
+
game.start
|
91
|
+
ui.was told_to(:display_winner).with(winner)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "asks ui to display a draw" do
|
95
|
+
game.start
|
96
|
+
ui.was told_to(:display_tied_game)
|
92
97
|
end
|
93
98
|
end
|
94
99
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'tic_tac_toe/spec_helper'
|
2
|
+
require 'tic_tac_toe/game_state_factory'
|
3
|
+
require 'tic_tac_toe/player_factory'
|
4
|
+
require 'mocks/player_factory'
|
5
|
+
require 'tic_tac_toe/player'
|
6
|
+
|
7
|
+
describe TicTacToe::GameStateFactory do
|
8
|
+
before(:each) do
|
9
|
+
@player_factory = MockPlayerFactory.new
|
10
|
+
@game_factory = TicTacToe::GameStateFactory.new(@player_factory)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "returns 4 types of games" do
|
14
|
+
@game_factory.types.size.should == 4
|
15
|
+
end
|
16
|
+
|
17
|
+
context "creates game state" do
|
18
|
+
before(:each) do
|
19
|
+
@human = TicTacToe::Player.new("Human", TicTacToe::VALUES[0], nil)
|
20
|
+
@computer = TicTacToe::Player.new("Computer", opponent_value(@human.value), nil)
|
21
|
+
|
22
|
+
@player_factory.will_have_human @human
|
23
|
+
@player_factory.will_have_computer @computer
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_game_state_creation(game_type, players)
|
27
|
+
game = @game_factory.create(game_type)
|
28
|
+
game.current_player.should == players[0]
|
29
|
+
game.change_player
|
30
|
+
game.current_player.should == players[1]
|
31
|
+
end
|
32
|
+
|
33
|
+
it "returns human vs computer game state" do
|
34
|
+
test_game_state_creation(1, [@human, @computer])
|
35
|
+
end
|
36
|
+
|
37
|
+
it "returns computer vs human game" do
|
38
|
+
test_game_state_creation(2, [@computer, @human])
|
39
|
+
end
|
40
|
+
|
41
|
+
it "returns user vs user game" do
|
42
|
+
@human2 = TicTacToe::Player.new("Human 2", opponent_value(@human.value), nil)
|
43
|
+
@player_factory.will_have_human @human, @human2
|
44
|
+
|
45
|
+
test_game_state_creation(3, [@human, @human2])
|
46
|
+
end
|
47
|
+
|
48
|
+
it "returns computer vs computer game" do
|
49
|
+
@computer2 = TicTacToe::Player.new("Computer 2", opponent_value(@computer.value), nil)
|
50
|
+
@player_factory.will_have_computer @computer, @computer2
|
51
|
+
|
52
|
+
test_game_state_creation(4, [@computer, @computer2])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it "raises an error when the game type doesn't exist" do
|
57
|
+
lambda{@game_factory.create(10)}.should raise_error(ArgumentError)
|
58
|
+
end
|
59
|
+
|
60
|
+
def opponent_value(value)
|
61
|
+
TicTacToe::Values.opponent(value)
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'tic_tac_toe/spec_helper'
|
2
|
+
require 'tic_tac_toe/board'
|
3
|
+
require 'tic_tac_toe/game_state'
|
4
|
+
require 'tic_tac_toe/player'
|
5
|
+
require 'tic_tac_toe/values'
|
6
|
+
|
7
|
+
describe TicTacToe::GameState do
|
8
|
+
attr_reader :game_state, :player1, :player2, :board
|
9
|
+
|
10
|
+
before(:each) do
|
11
|
+
@board = TicTacToe::Board.new
|
12
|
+
@player1 = TicTacToe::Player.new("player1", TicTacToe::VALUES[0], nil)
|
13
|
+
@player2 = TicTacToe::Player.new("player1", TicTacToe::VALUES[1], nil)
|
14
|
+
@game_state = TicTacToe::GameState.new([@player1, @player2], @board)
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
it "can read board" do
|
19
|
+
game_state.board.should == board
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "current player" do
|
23
|
+
it "starts with player 1 as the current player" do
|
24
|
+
game_state.current_player.should == player1
|
25
|
+
end
|
26
|
+
|
27
|
+
it "changes current player to player 2" do
|
28
|
+
game_state.current_player.should == player1
|
29
|
+
game_state.change_player
|
30
|
+
game_state.current_player.should == player2
|
31
|
+
end
|
32
|
+
|
33
|
+
it "changes current player to player 1 after two calls on change player" do
|
34
|
+
game_state.current_player.should == player1
|
35
|
+
game_state.change_player
|
36
|
+
game_state.change_player
|
37
|
+
game_state.current_player.should == player1
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "game over" do
|
42
|
+
it "is false when there is no mark" do
|
43
|
+
game_state.should_not be_game_over
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should be over when there is a winner" do
|
47
|
+
mark_winning_board(player1.value)
|
48
|
+
game_state.should be_game_over
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "winner" do
|
53
|
+
it "has no winner when there is no mark" do
|
54
|
+
game_state.winner.should be_nil
|
55
|
+
end
|
56
|
+
|
57
|
+
it "is player 1" do
|
58
|
+
mark_winning_board(player1.value)
|
59
|
+
game_state.winner.should == player1
|
60
|
+
end
|
61
|
+
|
62
|
+
it "is player 2" do
|
63
|
+
mark_winning_board(player2.value)
|
64
|
+
game_state.winner.should == player2
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def mark_winning_board(value)
|
69
|
+
[0, 4, 8].each do |move|
|
70
|
+
game_state.board.mark(move, value)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -2,6 +2,7 @@ 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'
|
5
6
|
|
6
7
|
describe TicTacToe::PlayerFactory do
|
7
8
|
|
@@ -32,27 +33,22 @@ describe TicTacToe::PlayerFactory do
|
|
32
33
|
end
|
33
34
|
|
34
35
|
context "computer player" do
|
35
|
-
before(:each) do
|
36
|
-
@board = "fake board"
|
37
|
-
end
|
38
|
-
|
39
36
|
it "returns a computer player with given value" do
|
40
37
|
computer_value = "Danny"
|
41
|
-
|
42
|
-
player = @factory.computer(@board, computer_value, opponent_value)
|
38
|
+
player = @factory.computer(computer_value)
|
43
39
|
player.value.should == computer_value
|
44
40
|
end
|
45
41
|
|
46
42
|
it "checks default strategy" do
|
47
|
-
@factory.computer
|
43
|
+
@factory.computer.strategy.should be_kind_of(TicTacToe::Strategy::Minimax)
|
48
44
|
end
|
49
45
|
|
50
46
|
it "checks default name" do
|
51
|
-
@factory.computer
|
47
|
+
@factory.computer.name.should == "Computer"
|
52
48
|
end
|
53
49
|
|
54
50
|
it "checks default value" do
|
55
|
-
@factory.computer
|
51
|
+
@factory.computer.value.should == "O"
|
56
52
|
end
|
57
53
|
end
|
58
54
|
|
@@ -1,32 +1,33 @@
|
|
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'
|
3
5
|
require 'mocks/strategy/dynamic'
|
4
6
|
|
5
7
|
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
|
6
15
|
|
7
16
|
it "gets name" do
|
8
|
-
name
|
9
|
-
player = TicTacToe::Player.new(name, nil, nil)
|
10
|
-
player.name.should == name
|
17
|
+
@player.name.should == @name
|
11
18
|
end
|
12
19
|
|
13
20
|
it "gets player value" do
|
14
|
-
value
|
15
|
-
player = TicTacToe::Player.new(nil, value, nil)
|
16
|
-
player.value.should == value
|
17
|
-
end
|
18
|
-
|
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
|
21
|
+
@player.value.should == @value
|
24
22
|
end
|
25
23
|
|
26
24
|
it "gets strategy" do
|
27
|
-
strategy
|
28
|
-
|
29
|
-
player.strategy.should == strategy
|
25
|
+
@player.strategy.should == @strategy
|
26
|
+
end
|
30
27
|
|
28
|
+
it "makes move" do
|
29
|
+
board = TicTacToe::Board.new
|
30
|
+
@player.move(board)
|
31
|
+
board.available_moves.should_not include(@move)
|
31
32
|
end
|
32
33
|
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(@board)
|
17
17
|
end
|
18
18
|
|
19
19
|
it "returns a number when user enters a number" do
|
@@ -1,156 +1,157 @@
|
|
1
1
|
require 'tic_tac_toe/spec_helper'
|
2
2
|
require 'tic_tac_toe/board'
|
3
3
|
require 'tic_tac_toe/strategy/minimax'
|
4
|
+
require 'tic_tac_toe/values'
|
4
5
|
|
5
6
|
describe TicTacToe::Strategy::Minimax, :slow_test => true do
|
6
7
|
|
7
8
|
before(:each) do
|
8
9
|
@board = TicTacToe::Board.new(3)
|
9
|
-
@
|
10
|
-
@
|
11
|
-
@strategy = TicTacToe::Strategy::Minimax.new(@
|
10
|
+
@computer_value = TicTacToe::VALUES[1]
|
11
|
+
@opponent_value = TicTacToe::Values.opponent(@computer_value)
|
12
|
+
@strategy = TicTacToe::Strategy::Minimax.new(@computer_value)
|
12
13
|
end
|
13
14
|
|
14
15
|
context "move" do
|
15
16
|
context "when there is only one position left" do
|
16
17
|
it "returns move when it's a winning move" do
|
17
|
-
mark((1...@board.size**2), @
|
18
|
-
@strategy.move.should == 0
|
18
|
+
mark((1...@board.size**2), @computer_value)
|
19
|
+
@strategy.move(@board).should == 0
|
19
20
|
end
|
20
21
|
|
21
22
|
it "returns the move when it's a tied" do
|
22
|
-
mark([0, 2, 5, 6], @
|
23
|
-
mark([1, 3, 4, 8], @
|
24
|
-
@strategy.move.should == 7
|
23
|
+
mark([0, 2, 5, 6], @computer_value)
|
24
|
+
mark([1, 3, 4, 8], @opponent_value)
|
25
|
+
@strategy.move(@board).should == 7
|
25
26
|
end
|
26
27
|
|
27
28
|
it "returns the move when opponent wins" do
|
28
|
-
mark((0...@board.size**2 - 1).to_a, @
|
29
|
-
@strategy.move.should == 8
|
29
|
+
mark((0...@board.size**2 - 1).to_a, @opponent_value)
|
30
|
+
@strategy.move(@board).should == 8
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
33
34
|
context "when there are two positions left" do
|
34
35
|
it "returns losing scores when the two moves are losing moves" do
|
35
|
-
mark((2...@board.size**2).to_a, @
|
36
|
-
@strategy.move.should == 0
|
36
|
+
mark((2...@board.size**2).to_a, @opponent_value)
|
37
|
+
@strategy.move(@board).should == 0
|
37
38
|
end
|
38
39
|
|
39
40
|
it "returns the first win move when the two moves are winning moves" do
|
40
|
-
mark((2...@board.size**2).to_a, @
|
41
|
-
@strategy.move.should == 0
|
41
|
+
mark((2...@board.size**2).to_a, @computer_value)
|
42
|
+
@strategy.move(@board).should == 0
|
42
43
|
end
|
43
44
|
|
44
45
|
it "returns the first tie move when the two moves are tie moves" do
|
45
|
-
mark([0, 2, 7], @
|
46
|
-
mark([1, 4, 6, 8], @
|
47
|
-
@strategy.move.should == 3
|
46
|
+
mark([0, 2, 7], @computer_value)
|
47
|
+
mark([1, 4, 6, 8], @opponent_value)
|
48
|
+
@strategy.move(@board).should == 3
|
48
49
|
end
|
49
50
|
|
50
51
|
it "returns win move when there are winning and losing moves" do
|
51
|
-
mark([0, 1, 3, 7], @
|
52
|
-
mark([2, 4, 5], @
|
53
|
-
@strategy.move.should == 6
|
52
|
+
mark([0, 1, 3, 7], @computer_value)
|
53
|
+
mark([2, 4, 5], @opponent_value)
|
54
|
+
@strategy.move(@board).should == 6
|
54
55
|
end
|
55
56
|
|
56
57
|
it "returns winning move when there are winning and tie moves" do
|
57
|
-
mark([0, 2, 3, 4], @
|
58
|
-
mark([1, 5, 8], @
|
59
|
-
@strategy.move.should == 6
|
58
|
+
mark([0, 2, 3, 4], @computer_value)
|
59
|
+
mark([1, 5, 8], @opponent_value)
|
60
|
+
@strategy.move(@board).should == 6
|
60
61
|
end
|
61
62
|
|
62
63
|
it "returns tied move when there are losing and tie moves" do
|
63
|
-
mark([2, 3, 4], @
|
64
|
-
mark([0, 5, 6, 7], @
|
65
|
-
@strategy.move.should == 8
|
64
|
+
mark([2, 3, 4], @computer_value)
|
65
|
+
mark([0, 5, 6, 7], @opponent_value)
|
66
|
+
@strategy.move(@board).should == 8
|
66
67
|
end
|
67
68
|
|
68
69
|
context "winning move appear later in the board" do
|
69
70
|
it "returns win move when winning move is later than losing move" do
|
70
|
-
mark([1, 2, 5, 7], @
|
71
|
-
mark([0, 3, 4], @
|
72
|
-
@strategy.move.should == 8
|
71
|
+
mark([1, 2, 5, 7], @computer_value)
|
72
|
+
mark([0, 3, 4], @opponent_value)
|
73
|
+
@strategy.move(@board).should == 8
|
73
74
|
end
|
74
75
|
|
75
76
|
it "returns winning move when winning move is later than tie move" do
|
76
|
-
mark([0, 2, 4, 5], @
|
77
|
-
mark([1, 3, 6], @
|
78
|
-
@strategy.move.should == 8
|
77
|
+
mark([0, 2, 4, 5], @computer_value)
|
78
|
+
mark([1, 3, 6], @opponent_value)
|
79
|
+
@strategy.move(@board).should == 8
|
79
80
|
end
|
80
81
|
|
81
82
|
it "returns tied move when there are losing and tie moves" do
|
82
|
-
mark([2, 3, 4], @
|
83
|
-
mark([0, 5, 6, 7], @
|
84
|
-
@strategy.move.should == 8
|
83
|
+
mark([2, 3, 4], @computer_value)
|
84
|
+
mark([0, 5, 6, 7], @opponent_value)
|
85
|
+
@strategy.move(@board).should == 8
|
85
86
|
end
|
86
87
|
end
|
87
88
|
end
|
88
89
|
|
89
90
|
context "when there are three moves left" do
|
90
91
|
it "chooses the winning move when there is one available" do
|
91
|
-
mark([1, 4], @
|
92
|
-
mark([0, 3, 2, 5], @
|
93
|
-
@strategy.move.should == 7
|
92
|
+
mark([1, 4], @computer_value)
|
93
|
+
mark([0, 3, 2, 5], @opponent_value)
|
94
|
+
@strategy.move(@board).should == 7
|
94
95
|
end
|
95
96
|
|
96
97
|
it "chooses a tie move when there are only losing and tie moves" do
|
97
|
-
mark([1, 4], @
|
98
|
-
mark([0, 2, 5, 7], @
|
99
|
-
@strategy.move.should == 8
|
98
|
+
mark([1, 4], @computer_value)
|
99
|
+
mark([0, 2, 5, 7], @opponent_value)
|
100
|
+
@strategy.move(@board).should == 8
|
100
101
|
end
|
101
102
|
end
|
102
103
|
|
103
104
|
context "when there are 4 moves left" do
|
104
105
|
it "chooses a winning move when one is available" do
|
105
|
-
mark([0, 4], @
|
106
|
-
mark([1, 2, 6], @
|
107
|
-
@strategy.move.should == 8
|
106
|
+
mark([0, 4], @computer_value)
|
107
|
+
mark([1, 2, 6], @opponent_value)
|
108
|
+
@strategy.move(@board).should == 8
|
108
109
|
end
|
109
110
|
|
110
111
|
it "chooses a move that would create 2 winning moves" do
|
111
|
-
mark([0, 6], @
|
112
|
-
mark([1, 3, 5], @
|
113
|
-
@strategy.move.should == 4
|
112
|
+
mark([0, 6], @computer_value)
|
113
|
+
mark([1, 3, 5], @opponent_value)
|
114
|
+
@strategy.move(@board).should == 4
|
114
115
|
end
|
115
116
|
end
|
116
117
|
end
|
117
118
|
|
118
119
|
it "chooses the winning move when available" do
|
119
|
-
mark([1, 4], @
|
120
|
-
mark([0], @
|
121
|
-
@strategy.move.should == 7
|
120
|
+
mark([1, 4], @computer_value)
|
121
|
+
mark([0], @opponent_value)
|
122
|
+
@strategy.move(@board).should == 7
|
122
123
|
end
|
123
124
|
|
124
125
|
it "chooses the winning move when available" do
|
125
|
-
mark([0, 4], @
|
126
|
-
mark([1, 2], @
|
127
|
-
@strategy.move.should == 8
|
126
|
+
mark([0, 4], @computer_value)
|
127
|
+
mark([1, 2], @opponent_value)
|
128
|
+
@strategy.move(@board).should == 8
|
128
129
|
end
|
129
130
|
|
130
131
|
it "chooses a blocking move when there is no winning move" do
|
131
|
-
mark([2], @
|
132
|
-
mark([0, 4], @
|
133
|
-
@strategy.move.should == 8
|
132
|
+
mark([2], @computer_value)
|
133
|
+
mark([0, 4], @opponent_value)
|
134
|
+
@strategy.move(@board).should == 8
|
134
135
|
end
|
135
136
|
|
136
137
|
it "chooses a blocking move when there is no winning move" do
|
137
|
-
mark([2], @
|
138
|
-
mark([1, 4], @
|
139
|
-
@strategy.move.should == 7
|
138
|
+
mark([2], @computer_value)
|
139
|
+
mark([1, 4], @opponent_value)
|
140
|
+
@strategy.move(@board).should == 7
|
140
141
|
end
|
141
142
|
|
142
143
|
it "chooses the middle square when computer is the second player" do
|
143
|
-
mark([0], @
|
144
|
-
@strategy.move.should == 4
|
144
|
+
mark([0], @opponent_value)
|
145
|
+
@strategy.move(@board).should == 4
|
145
146
|
end
|
146
147
|
|
147
148
|
it "chooses the first corner of the board when the middle square is taken as a second player" do
|
148
|
-
mark([4], @
|
149
|
-
@strategy.move.should == 0
|
149
|
+
mark([4], @opponent_value)
|
150
|
+
@strategy.move(@board).should == 0
|
150
151
|
end
|
151
152
|
|
152
153
|
it "chooses the middle square on the first move" do
|
153
|
-
@strategy.move.should == 4
|
154
|
+
@strategy.move(@board).should == 4
|
154
155
|
end
|
155
156
|
|
156
157
|
def move_node(move, score)
|
@@ -79,7 +79,7 @@ describe TicTacToe::Console do
|
|
79
79
|
it "displays winner" do
|
80
80
|
player = TicTacToe::Player.new("Todd", "X", nil)
|
81
81
|
@console.display_winner(player)
|
82
|
-
@output.string.should == "Todd(X)
|
82
|
+
@output.string.should == "Todd(X) wins!\n"
|
83
83
|
end
|
84
84
|
|
85
85
|
it "display tied game" do
|