tic_tac_toes 0.0.2 → 0.0.3
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/.travis.yml +7 -0
- data/Gemfile.lock +1 -1
- data/README.md +2 -0
- data/Rakefile +2 -2
- data/bin/tic_tac_toes +21 -9
- data/lib/command_line/menu.rb +11 -12
- data/lib/command_line/{io.rb → prompt.rb} +1 -1
- data/lib/command_line/runner.rb +18 -18
- data/lib/tic_tac_toes/board_factory.rb +9 -0
- data/lib/tic_tac_toes/game_state.rb +27 -0
- data/lib/tic_tac_toes/game_state_factory.rb +14 -0
- data/lib/tic_tac_toes/history.rb +3 -3
- data/lib/tic_tac_toes/io.rb +91 -0
- data/lib/tic_tac_toes/move_strategies/easy_ai.rb +11 -0
- data/lib/tic_tac_toes/move_strategies/hard_ai.rb +59 -0
- data/lib/tic_tac_toes/move_strategies/human.rb +18 -0
- data/lib/tic_tac_toes/move_strategies/medium_ai.rb +13 -0
- data/lib/tic_tac_toes/player.rb +7 -7
- data/lib/tic_tac_toes/player_factory.rb +13 -9
- data/lib/tic_tac_toes/rules.rb +1 -1
- data/lib/tic_tac_toes/strings.rb +3 -2
- data/lib/tic_tac_toes/version.rb +1 -1
- data/spec/command_line/menu_spec.rb +40 -44
- data/spec/command_line/runner_spec.rb +23 -101
- data/spec/database/pg_wrapper_spec.rb +0 -1
- data/spec/test_board_generator.rb +15 -0
- data/spec/tic_tac_toes/board_factory_spec.rb +13 -0
- data/spec/tic_tac_toes/board_spec.rb +20 -25
- data/spec/tic_tac_toes/game_state_factory_spec.rb +15 -0
- data/spec/tic_tac_toes/game_state_spec.rb +66 -0
- data/spec/tic_tac_toes/history_spec.rb +3 -4
- data/spec/tic_tac_toes/io_spec.rb +163 -0
- data/spec/tic_tac_toes/move_strategies/easy_ai_spec.rb +19 -0
- data/spec/tic_tac_toes/move_strategies/hard_ai_spec.rb +95 -0
- data/spec/tic_tac_toes/move_strategies/human_spec.rb +31 -0
- data/spec/tic_tac_toes/move_strategies/medium_ai_spec.rb +21 -0
- data/spec/tic_tac_toes/player_factory_spec.rb +13 -16
- data/spec/tic_tac_toes/player_spec.rb +14 -16
- data/spec/tic_tac_toes/rules_spec.rb +31 -41
- data/spec/tic_tac_toes/strings_spec.rb +0 -1
- metadata +32 -19
- data/lib/tic_tac_toes/easy_ai.rb +0 -9
- data/lib/tic_tac_toes/hard_ai.rb +0 -57
- data/lib/tic_tac_toes/io_interface.rb +0 -96
- data/lib/tic_tac_toes/medium_ai.rb +0 -11
- data/spec/tic_tac_toes/easy_ai_spec.rb +0 -20
- data/spec/tic_tac_toes/hard_ai_spec.rb +0 -103
- data/spec/tic_tac_toes/io_interface_spec.rb +0 -175
- data/spec/tic_tac_toes/medium_ai_spec.rb +0 -22
- data/spec/tic_tac_toes/spec_helper.rb +0 -13
- /data/lib/{tic_tac_toes/tasks → tasks}/destroy_databases.rake +0 -0
- /data/lib/{tic_tac_toes/tasks → tasks}/set_up_databases.rake +0 -0
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'tic_tac_toes/spec_helper'
|
2
|
-
require 'tic_tac_toes/easy_ai'
|
3
|
-
|
4
|
-
describe TicTacToes::EasyAI do
|
5
|
-
describe '#make_move' do
|
6
|
-
let(:players) { double("players") }
|
7
|
-
let(:ai) { TicTacToes::EasyAI }
|
8
|
-
|
9
|
-
it "returns a randomly-selected valid move" do
|
10
|
-
structure = [ :O, nil, nil,
|
11
|
-
nil, :X, nil,
|
12
|
-
nil, :X, nil]
|
13
|
-
board = generate_board(structure)
|
14
|
-
valid_moves = [1, 2, 3, 5, 6, 8]
|
15
|
-
|
16
|
-
move = ai.make_move(board, players)
|
17
|
-
expect(valid_moves).to include(move)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,103 +0,0 @@
|
|
1
|
-
require 'tic_tac_toes/hard_ai'
|
2
|
-
require 'tic_tac_toes/player'
|
3
|
-
require 'tic_tac_toes/spec_helper'
|
4
|
-
|
5
|
-
describe TicTacToes::HardAI do
|
6
|
-
let(:ai) { TicTacToes::HardAI }
|
7
|
-
let(:x) { TicTacToes::Player.new("decider", "x", false, "interface") }
|
8
|
-
let(:o) { TicTacToes::Player.new(ai, "o", true, "interface") }
|
9
|
-
let(:players) { [o, x] }
|
10
|
-
|
11
|
-
|
12
|
-
describe '#make_move' do
|
13
|
-
it "returns the best move" do
|
14
|
-
structure = [x, nil, nil,
|
15
|
-
o, o, nil,
|
16
|
-
x, nil, x]
|
17
|
-
board = generate_board(structure)
|
18
|
-
best_move = 5
|
19
|
-
|
20
|
-
expect(ai.make_move(board, players)).to eql(best_move)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
|
25
|
-
describe '#minimax' do
|
26
|
-
it "returns the correct score for a pre-win board" do
|
27
|
-
structure = [x, nil, nil,
|
28
|
-
o, o, nil,
|
29
|
-
x, nil, x]
|
30
|
-
board = generate_board(structure)
|
31
|
-
win_score = 1
|
32
|
-
|
33
|
-
expect(ai.minimax(board, :max, players)).to eql(win_score)
|
34
|
-
end
|
35
|
-
|
36
|
-
it "returns the correct score for a pre-loss board" do
|
37
|
-
structure = [ o, o, x,
|
38
|
-
nil, nil, nil,
|
39
|
-
x, nil, x]
|
40
|
-
board = generate_board(structure)
|
41
|
-
loss_score = -1
|
42
|
-
|
43
|
-
expect(ai.minimax(board, :max, players)).to eql(loss_score)
|
44
|
-
end
|
45
|
-
|
46
|
-
it "returns the correct score for a pre-draw board" do
|
47
|
-
structure = [x, x, o,
|
48
|
-
o, nil, x,
|
49
|
-
x, o, x]
|
50
|
-
board = generate_board(structure)
|
51
|
-
draw_score = 0
|
52
|
-
|
53
|
-
expect(ai.minimax(board, :max, players)).to eql(draw_score)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
|
58
|
-
describe '#generate_board' do
|
59
|
-
it "returns a board based on a token, a space, and an existing board" do
|
60
|
-
token, space = o, 3
|
61
|
-
structure = [ x, nil, nil,
|
62
|
-
nil, o, nil,
|
63
|
-
x, nil, nil]
|
64
|
-
board = generate_board(structure)
|
65
|
-
|
66
|
-
new_board = ai.generate_board(token, space, board)
|
67
|
-
expect(new_board.space(space)).to eql(token)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
|
72
|
-
describe '#score' do
|
73
|
-
it "returns the correct score when HardAI has won" do
|
74
|
-
structure = [ o, nil, nil,
|
75
|
-
nil, o, nil,
|
76
|
-
nil, nil, o]
|
77
|
-
board = generate_board(structure)
|
78
|
-
win_score = 1
|
79
|
-
|
80
|
-
expect(ai.score(board, players)).to eql(win_score)
|
81
|
-
end
|
82
|
-
|
83
|
-
it "returns the correct score when no one has won" do
|
84
|
-
structure = [o, o, x,
|
85
|
-
x, x, o,
|
86
|
-
o, x, o]
|
87
|
-
board = generate_board(structure)
|
88
|
-
draw_score = 0
|
89
|
-
|
90
|
-
expect(ai.score(board, players)).to eql(draw_score)
|
91
|
-
end
|
92
|
-
|
93
|
-
it "returns the correct score when the opponent has won" do
|
94
|
-
structure = [ x, nil, nil,
|
95
|
-
nil, x, nil,
|
96
|
-
nil, nil, x]
|
97
|
-
board = generate_board(structure)
|
98
|
-
loss_score = -1
|
99
|
-
|
100
|
-
expect(ai.score(board, players)).to eql(loss_score)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
@@ -1,175 +0,0 @@
|
|
1
|
-
require 'tic_tac_toes/board'
|
2
|
-
require 'tic_tac_toes/io_interface'
|
3
|
-
require 'tic_tac_toes/spec_helper'
|
4
|
-
require 'tic_tac_toes/strings'
|
5
|
-
|
6
|
-
describe TicTacToes::IOInterface do
|
7
|
-
let(:strings) { TicTacToes::Strings }
|
8
|
-
let(:io) { double("io", solicit_input: 0, display: true, display_red: true) }
|
9
|
-
let(:io_interface) { TicTacToes::IOInterface.new(io) }
|
10
|
-
|
11
|
-
|
12
|
-
describe '#make_move' do
|
13
|
-
it "displays a move solicitation" do
|
14
|
-
expect(io_interface).to receive(:move_solicitation)
|
15
|
-
io_interface.make_move("_board", "_players")
|
16
|
-
end
|
17
|
-
|
18
|
-
context 'when given not-integer-like input' do
|
19
|
-
let(:not_integer_like) { "string" }
|
20
|
-
let(:integer_like) { "100" }
|
21
|
-
|
22
|
-
it "displays a not an integer error" do
|
23
|
-
allow(io).to receive(:solicit_input).and_return(not_integer_like, integer_like)
|
24
|
-
|
25
|
-
expect(io_interface).to receive(:not_an_integer_error).once
|
26
|
-
io_interface.make_move("_board", "_players")
|
27
|
-
end
|
28
|
-
|
29
|
-
it "only returns a move (converted to integer) once it gets integer-like input" do
|
30
|
-
allow(io).to receive(:solicit_input).and_return(not_integer_like, integer_like)
|
31
|
-
|
32
|
-
expect(io_interface.make_move("_board", "_players")).to eq(100)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
|
-
describe '#get_row_size' do
|
39
|
-
it "displays a row size solicitation" do
|
40
|
-
expect(io_interface).to receive(:row_size_solicitation)
|
41
|
-
io_interface.get_row_size
|
42
|
-
end
|
43
|
-
|
44
|
-
context 'when given not-integer-like input' do
|
45
|
-
let(:not_integer_like) { "string" }
|
46
|
-
let(:integer_like) { "100" }
|
47
|
-
|
48
|
-
it "displays a not an integer error" do
|
49
|
-
allow(io).to receive(:solicit_input).and_return(not_integer_like, integer_like)
|
50
|
-
|
51
|
-
expect(io_interface).to receive(:not_an_integer_error).once
|
52
|
-
io_interface.get_row_size
|
53
|
-
end
|
54
|
-
|
55
|
-
it "only returns a row size (converted to integer) once it gets integer-like input" do
|
56
|
-
allow(io).to receive(:solicit_input).and_return(not_integer_like, integer_like)
|
57
|
-
|
58
|
-
expect(io_interface.get_row_size).to eq(100)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
|
64
|
-
describe '#get_token' do
|
65
|
-
let(:player) { double("player") }
|
66
|
-
|
67
|
-
it "displays a token solicitation with the name of the player whose token is to be set" do
|
68
|
-
expect(io_interface).to receive(:token_solicitation).with(player)
|
69
|
-
io_interface.get_token(player)
|
70
|
-
end
|
71
|
-
|
72
|
-
it "returns the user input" do
|
73
|
-
token = "X"
|
74
|
-
allow(io).to receive(:solicit_input) { token }
|
75
|
-
|
76
|
-
expect(io_interface.get_token(player)).to equal(token)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
|
81
|
-
describe '#get_difficulty' do
|
82
|
-
let(:difficulty) { "HARD" }
|
83
|
-
|
84
|
-
it "displays a difficulty solicitation" do
|
85
|
-
allow(io).to receive(:solicit_input) { difficulty }
|
86
|
-
|
87
|
-
expect(io_interface).to receive(:difficulty_solicitation)
|
88
|
-
io_interface.get_difficulty
|
89
|
-
end
|
90
|
-
|
91
|
-
it "returns the user input (downcased and converted into a symbol)" do
|
92
|
-
allow(io).to receive(:solicit_input) { difficulty }
|
93
|
-
|
94
|
-
expect(io_interface.get_difficulty).to equal(:hard)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
|
99
|
-
describe '#draw_board' do
|
100
|
-
it "displays a board string" do
|
101
|
-
board = TicTacToes::Board.new
|
102
|
-
board_string = strings.board(board)
|
103
|
-
|
104
|
-
expect(io).to receive(:display).with(board_string)
|
105
|
-
io_interface.draw_board(board)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
|
110
|
-
describe '#invalid_row_size_error' do
|
111
|
-
it "displays a red invalid row size message" do
|
112
|
-
expect(io).to receive(:display_red).with(strings::INVALID_ROW_SIZE)
|
113
|
-
io_interface.invalid_row_size_error
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
|
118
|
-
describe '#invalid_token_error' do
|
119
|
-
it "displays a red invalid token message" do
|
120
|
-
expect(io).to receive(:display_red).with(strings::INVALID_TOKEN)
|
121
|
-
io_interface.invalid_token_error
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
|
126
|
-
describe '#invalid_difficulty_error' do
|
127
|
-
it "displays a red invalid difficulty message" do
|
128
|
-
expect(io).to receive(:display_red).with(strings::INVALID_DIFFICULTY)
|
129
|
-
io_interface.invalid_difficulty_error
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
|
134
|
-
describe '#invalid_move_error' do
|
135
|
-
it "displays a red invalid move message" do
|
136
|
-
expect(io).to receive(:display_red).with(strings::INVALID_MOVE)
|
137
|
-
io_interface.invalid_move_error
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
|
142
|
-
describe '#thinking_notification' do
|
143
|
-
it "displays a red thinking message" do
|
144
|
-
expect(io).to receive(:display_red).with(strings::THINKING)
|
145
|
-
io_interface.thinking_notification
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
|
150
|
-
describe '#game_over_notification' do
|
151
|
-
it "displays a game over message with the name of the winner" do
|
152
|
-
winner = :X
|
153
|
-
game_over_message = strings.game_over_notification(winner)
|
154
|
-
|
155
|
-
expect(io).to receive(:display).with(game_over_message)
|
156
|
-
io_interface.game_over_notification(winner)
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
|
161
|
-
describe '#red' do
|
162
|
-
it "calls its IO's red method with the passed message" do
|
163
|
-
expect(io).to receive(:red).with("message")
|
164
|
-
io_interface.red("message")
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
|
169
|
-
describe '#blue' do
|
170
|
-
it "calls its IO's blue method with the passed message" do
|
171
|
-
expect(io).to receive(:blue).with("message")
|
172
|
-
io_interface.blue("message")
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
require 'tic_tac_toes/medium_ai'
|
2
|
-
require 'tic_tac_toes/spec_helper'
|
3
|
-
|
4
|
-
describe TicTacToes::MediumAI do
|
5
|
-
let(:ai) { TicTacToes::MediumAI }
|
6
|
-
let(:x) { TicTacToes::Player.new("decider", "x", false, "interface") }
|
7
|
-
let(:o) { TicTacToes::Player.new(ai, "o", true, "interface") }
|
8
|
-
let(:players) { [x, o] }
|
9
|
-
|
10
|
-
describe '#make_move' do
|
11
|
-
it "makes a valid move (based on either EasyAI or HardAI)" do
|
12
|
-
structure = [ o, o, x,
|
13
|
-
nil, x, nil,
|
14
|
-
nil, x, nil]
|
15
|
-
board = generate_board(structure)
|
16
|
-
valid_moves = [3, 5, 6, 8]
|
17
|
-
|
18
|
-
move = ai.make_move(board, players)
|
19
|
-
expect(valid_moves).to include(move)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,13 +0,0 @@
|
|
1
|
-
require 'tic_tac_toes/board'
|
2
|
-
|
3
|
-
def generate_board(structure)
|
4
|
-
board_size = structure.count
|
5
|
-
row_size = Math.sqrt(board_size)
|
6
|
-
board = TicTacToes::Board.new(row_size: row_size)
|
7
|
-
|
8
|
-
structure.each_with_index do |player, index|
|
9
|
-
board.place(player, index)
|
10
|
-
end
|
11
|
-
|
12
|
-
board
|
13
|
-
end
|
File without changes
|
File without changes
|