tic_tac_toes 0.1.2 → 0.1.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/Gemfile.lock +1 -1
- data/lib/tic_tac_toes/command_line/history_reader.rb +28 -0
- data/lib/tic_tac_toes/command_line/runner.rb +2 -1
- data/lib/tic_tac_toes/core/game_state.rb +19 -5
- data/lib/tic_tac_toes/core/history.rb +9 -5
- data/lib/tic_tac_toes/core/io.rb +1 -0
- data/lib/tic_tac_toes/core/move_strategies/easy_ai.rb +14 -0
- data/lib/tic_tac_toes/core/move_strategies/hard_ai.rb +16 -3
- data/lib/tic_tac_toes/core/move_strategies/human.rb +4 -0
- data/lib/tic_tac_toes/core/move_strategies/medium_ai.rb +13 -0
- data/lib/tic_tac_toes/core/move_strategies/types.rb +8 -0
- data/lib/tic_tac_toes/database/pg_wrapper.rb +7 -4
- data/lib/tic_tac_toes/tasks/set_up_databases.rake +1 -0
- data/lib/tic_tac_toes/ui/serializer.rb +8 -14
- data/lib/tic_tac_toes/version.rb +1 -1
- data/spec/tic_tac_toes/command_line/history_reader_spec.rb +48 -0
- data/spec/tic_tac_toes/core/game_state_spec.rb +24 -6
- data/spec/tic_tac_toes/core/history_spec.rb +10 -0
- data/spec/tic_tac_toes/core/io_spec.rb +1 -1
- data/spec/tic_tac_toes/core/move_strategies/easy_ai_spec.rb +13 -1
- data/spec/tic_tac_toes/core/move_strategies/hard_ai_spec.rb +12 -0
- data/spec/tic_tac_toes/core/move_strategies/human_spec.rb +6 -0
- data/spec/tic_tac_toes/core/move_strategies/medium_ai_spec.rb +12 -0
- data/spec/tic_tac_toes/database/pg_wrapper_spec.rb +4 -0
- data/spec/tic_tac_toes/ui/serializer_spec.rb +2 -2
- metadata +6 -4
- data/spec/tic_tac_toes/command_line/runner_spec.rb +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 22ba02e7e5275ba82986cd4bc1c0afa6702085e7
|
4
|
+
data.tar.gz: fddb7424a82204ebc710edb266c25162f46edc9f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 04467495e7afeaf413c8b66714e61a4efa22e4da5dbc37ea1d6dfad2e8e0a48584156c274a15130b4ff522c67c834256d335a9c567d890c44f83f2397ec5a2ab
|
7
|
+
data.tar.gz: a0724449d160d43969c1565c8dc030f40c18d72fdbb313816811387cd4e465eff1432829710fe3eeba818121e0661dce941231ac368833967d39d9e8c5bf1297
|
data/Gemfile.lock
CHANGED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'tic_tac_toes/command_line/prompt'
|
2
|
+
|
3
|
+
module TicTacToes
|
4
|
+
module CommandLine
|
5
|
+
class HistoryReader
|
6
|
+
def initialize(wrapper)
|
7
|
+
@wrapper = wrapper
|
8
|
+
end
|
9
|
+
|
10
|
+
def display_game_histories
|
11
|
+
game_histories = @wrapper.read_game_histories
|
12
|
+
game_histories.each { |history| Prompt.display(game_history_string(history)) }
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def game_history_string(history)
|
17
|
+
history_string = ''
|
18
|
+
history_string << "Board size: #{history.board_size.to_s}\n"
|
19
|
+
history_string << "Difficulty: #{history.difficulty}\n"
|
20
|
+
history_string << "Winner: #{history.winner}\n"
|
21
|
+
history_string << "Move history:\n"
|
22
|
+
history.moves.each { |move| history_string << " #{move.join(' -> ')}\n" }
|
23
|
+
history_string << "\n"
|
24
|
+
history_string
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -12,6 +12,7 @@ module TicTacToes
|
|
12
12
|
def run
|
13
13
|
board, players = @menu.get_board, @menu.get_players
|
14
14
|
game_state = TicTacToes::Core::GameState.new(board, players, @history)
|
15
|
+
game_state.start_game
|
15
16
|
|
16
17
|
take_turn(game_state) until game_state.game_over?
|
17
18
|
end_game(game_state)
|
@@ -31,7 +32,7 @@ module TicTacToes
|
|
31
32
|
@io.draw_board(game_state.board)
|
32
33
|
|
33
34
|
winner = game_state.determine_winner
|
34
|
-
game_state.
|
35
|
+
game_state.end_game(winner)
|
35
36
|
|
36
37
|
@io.game_over_notification(winner)
|
37
38
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'tic_tac_toes/core/rules'
|
2
|
+
require 'tic_tac_toes/core/move_strategies/types'
|
2
3
|
|
3
4
|
module TicTacToes
|
4
5
|
module Core
|
@@ -9,9 +10,11 @@ module TicTacToes
|
|
9
10
|
@board = board
|
10
11
|
@players = players
|
11
12
|
@history = history
|
12
|
-
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
+
def start_game
|
16
|
+
record_board_size
|
17
|
+
record_difficulty
|
15
18
|
end
|
16
19
|
|
17
20
|
def place_move(space)
|
@@ -31,17 +34,28 @@ module TicTacToes
|
|
31
34
|
@players.rotate!
|
32
35
|
end
|
33
36
|
|
34
|
-
def
|
37
|
+
def end_game(winner)
|
35
38
|
@history.record_winner(winner)
|
36
39
|
@history.persist
|
37
40
|
end
|
38
41
|
|
39
42
|
def game_over?
|
40
|
-
|
43
|
+
Rules.game_over?(@board, @players)
|
41
44
|
end
|
42
45
|
|
43
46
|
def determine_winner
|
44
|
-
|
47
|
+
Rules.determine_winner(@board, @players)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def record_board_size
|
53
|
+
@history.record_board_size(@board.size)
|
54
|
+
end
|
55
|
+
|
56
|
+
def record_difficulty
|
57
|
+
computer_player = @players.detect { |player| player.move_strategy.type == MoveStrategies::COMPUTER }
|
58
|
+
@history.record_difficulty(computer_player.move_strategy)
|
45
59
|
end
|
46
60
|
end
|
47
61
|
end
|
@@ -1,29 +1,33 @@
|
|
1
1
|
module TicTacToes
|
2
2
|
module Core
|
3
3
|
class History
|
4
|
-
attr_reader :board_size, :moves, :winner
|
4
|
+
attr_reader :board_size, :difficulty, :moves, :winner
|
5
5
|
|
6
|
-
def initialize(
|
7
|
-
@
|
6
|
+
def initialize(wrapper)
|
7
|
+
@wrapper = wrapper
|
8
8
|
end
|
9
9
|
|
10
10
|
def record_board_size(size)
|
11
11
|
@board_size = size
|
12
12
|
end
|
13
13
|
|
14
|
+
def record_difficulty(difficulty)
|
15
|
+
@difficulty = difficulty.to_s
|
16
|
+
end
|
17
|
+
|
14
18
|
def record_move(move)
|
15
19
|
@moves ||= []
|
16
20
|
@moves << move
|
17
21
|
end
|
18
22
|
|
19
23
|
def record_winner(winner)
|
20
|
-
winner =
|
24
|
+
winner = 'Draw' if winner.nil?
|
21
25
|
winner = winner.token unless winner.is_a? String
|
22
26
|
@winner = winner
|
23
27
|
end
|
24
28
|
|
25
29
|
def persist
|
26
|
-
@
|
30
|
+
@wrapper.record_game_history(self)
|
27
31
|
end
|
28
32
|
end
|
29
33
|
end
|
data/lib/tic_tac_toes/core/io.rb
CHANGED
@@ -1,7 +1,21 @@
|
|
1
|
+
require 'tic_tac_toes/core/move_strategies/types'
|
2
|
+
|
1
3
|
module TicTacToes
|
2
4
|
module Core
|
3
5
|
module MoveStrategies
|
4
6
|
module EasyAI
|
7
|
+
def self.to_s
|
8
|
+
'Easy AI'
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.type
|
12
|
+
MoveStrategies::COMPUTER
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.ai_type
|
16
|
+
'EASY_AI'
|
17
|
+
end
|
18
|
+
|
5
19
|
def self.move(game_state)
|
6
20
|
game_state.board.open_spaces.sample
|
7
21
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'tic_tac_toes/core/move_strategies/types'
|
1
2
|
require 'tic_tac_toes/core/rules'
|
2
3
|
|
3
4
|
module TicTacToes
|
@@ -6,6 +7,18 @@ module TicTacToes
|
|
6
7
|
module HardAI
|
7
8
|
ALPHA, BETA, DEPTH = -100, 100, 0
|
8
9
|
|
10
|
+
def self.to_s
|
11
|
+
'Hard AI'
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.type
|
15
|
+
MoveStrategies::COMPUTER
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.ai_type
|
19
|
+
'HARD_AI'
|
20
|
+
end
|
21
|
+
|
9
22
|
def self.move(game_state)
|
10
23
|
board = game_state.board
|
11
24
|
|
@@ -54,10 +67,10 @@ module TicTacToes
|
|
54
67
|
winner = game_state.determine_winner
|
55
68
|
if winner.nil?
|
56
69
|
0
|
57
|
-
elsif winner.move_strategy.
|
58
|
-
-100
|
59
|
-
else
|
70
|
+
elsif winner.move_strategy.type == MoveStrategies::COMPUTER
|
60
71
|
100 - depth
|
72
|
+
else
|
73
|
+
-100
|
61
74
|
end
|
62
75
|
end
|
63
76
|
|
@@ -1,10 +1,23 @@
|
|
1
1
|
require 'tic_tac_toes/core/move_strategies/easy_ai'
|
2
2
|
require 'tic_tac_toes/core/move_strategies/hard_ai'
|
3
|
+
require 'tic_tac_toes/core/move_strategies/types'
|
3
4
|
|
4
5
|
module TicTacToes
|
5
6
|
module Core
|
6
7
|
module MoveStrategies
|
7
8
|
module MediumAI
|
9
|
+
def self.to_s
|
10
|
+
'Medium AI'
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.type
|
14
|
+
MoveStrategies::COMPUTER
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.ai_type
|
18
|
+
'MEDIUM_AI'
|
19
|
+
end
|
20
|
+
|
8
21
|
def self.move(game_state)
|
9
22
|
move_strategy = [EasyAI, HardAI, HardAI].sample
|
10
23
|
move_strategy.move(game_state)
|
@@ -10,7 +10,7 @@ module TicTacToes
|
|
10
10
|
|
11
11
|
def record_game_history(history)
|
12
12
|
connection = establish_connection
|
13
|
-
|
13
|
+
record_game_info(history, connection)
|
14
14
|
record_moves(history, connection)
|
15
15
|
end
|
16
16
|
|
@@ -22,7 +22,8 @@ module TicTacToes
|
|
22
22
|
games_result.each_row do |row|
|
23
23
|
game_id = row[0]
|
24
24
|
board_size = row[1].to_i
|
25
|
-
|
25
|
+
difficulty = row[2]
|
26
|
+
winner = row[3]
|
26
27
|
moves_result = connection.exec("SELECT * FROM moves WHERE game = #{game_id}")
|
27
28
|
|
28
29
|
history = Core::History.new(self)
|
@@ -32,6 +33,7 @@ module TicTacToes
|
|
32
33
|
history.record_move([token, space])
|
33
34
|
end
|
34
35
|
history.record_board_size(board_size)
|
36
|
+
history.record_difficulty(difficulty)
|
35
37
|
history.record_winner(winner)
|
36
38
|
|
37
39
|
games << history
|
@@ -46,9 +48,10 @@ module TicTacToes
|
|
46
48
|
PG.connect(dbname: @database)
|
47
49
|
end
|
48
50
|
|
49
|
-
def
|
50
|
-
connection.exec("INSERT INTO games (board_size, winner) VALUES (
|
51
|
+
def record_game_info(history, connection)
|
52
|
+
connection.exec("INSERT INTO games (board_size, difficulty, winner) VALUES (
|
51
53
|
#{history.board_size},
|
54
|
+
'#{history.difficulty}',
|
52
55
|
'#{history.winner}')")
|
53
56
|
end
|
54
57
|
|
@@ -32,6 +32,7 @@ def create_production_tables_if_not_exist
|
|
32
32
|
connection.exec("CREATE TABLE IF NOT EXISTS games (
|
33
33
|
id serial primary key,
|
34
34
|
board_size integer,
|
35
|
+
difficulty varchar,
|
35
36
|
winner varchar)")
|
36
37
|
connection.exec("CREATE TABLE IF NOT EXISTS moves (
|
37
38
|
game integer REFERENCES games (id),
|
@@ -31,20 +31,10 @@ module TicTacToes
|
|
31
31
|
replace_players_with_tokens(structure_with_players)
|
32
32
|
end
|
33
33
|
|
34
|
-
def self.
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
if player.move_strategy == Core::PlayerFactory::AIS.fetch(Core::PlayerFactory::EASY_AI)
|
39
|
-
type = 'EASY_AI'
|
40
|
-
elsif player.move_strategy == Core::PlayerFactory::AIS.fetch(Core::PlayerFactory::MEDIUM_AI)
|
41
|
-
type = 'MEDIUM_AI'
|
42
|
-
elsif player.move_strategy == Core::PlayerFactory::AIS.fetch(Core::PlayerFactory::HARD_AI)
|
43
|
-
type = 'HARD_AI'
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
type
|
34
|
+
def self.ai_type_from_game_state(game_state)
|
35
|
+
computer = Core::MoveStrategies::COMPUTER
|
36
|
+
computer_player = game_state.players.detect { |player| player.move_strategy.type == computer }
|
37
|
+
computer_player.move_strategy.ai_type
|
48
38
|
end
|
49
39
|
|
50
40
|
private
|
@@ -83,6 +73,10 @@ module TicTacToes
|
|
83
73
|
nil
|
84
74
|
end
|
85
75
|
|
76
|
+
def record_difficulty(difficulty)
|
77
|
+
nil
|
78
|
+
end
|
79
|
+
|
86
80
|
def record_move(move)
|
87
81
|
nil
|
88
82
|
end
|
data/lib/tic_tac_toes/version.rb
CHANGED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'tic_tac_toes/command_line/history_reader'
|
2
|
+
|
3
|
+
describe TicTacToes::CommandLine::HistoryReader do
|
4
|
+
before do
|
5
|
+
@history_double = double('history',
|
6
|
+
board_size: 9,
|
7
|
+
difficulty: 'Medium AI',
|
8
|
+
winner: 'X',
|
9
|
+
moves: [['A', 0], ['B', 4]])
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#display_game_histories' do
|
13
|
+
it 'Displays something for each game history' do
|
14
|
+
histories_array = [@history_double, @history_double]
|
15
|
+
wrapper = double('wrapper', read_game_histories: histories_array)
|
16
|
+
|
17
|
+
expect(TicTacToes::CommandLine::Prompt).to receive(:display).twice
|
18
|
+
TicTacToes::CommandLine::HistoryReader.new(wrapper).display_game_histories
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#game_history_string' do
|
23
|
+
before do
|
24
|
+
wrapper_double = double('wrapper')
|
25
|
+
@history_reader = TicTacToes::CommandLine::HistoryReader.new(wrapper_double)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'Returns a string that includes the game history’s board size' do
|
29
|
+
history_string = @history_reader.game_history_string(@history_double)
|
30
|
+
expect(history_string).to include('9')
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'Returns a string that includes the game history’s difficulty' do
|
34
|
+
history_string = @history_reader.game_history_string(@history_double)
|
35
|
+
expect(history_string).to include('Medium AI')
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'Returns a string that includes the game history’s winner' do
|
39
|
+
history_string = @history_reader.game_history_string(@history_double)
|
40
|
+
expect(history_string).to include('X')
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'Returns a string that includes the game history’s move history' do
|
44
|
+
history_string = @history_reader.game_history_string(@history_double)
|
45
|
+
expect(history_string).to include('A', '0', 'B', '4')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -1,15 +1,33 @@
|
|
1
1
|
require 'tic_tac_toes/core/game_state'
|
2
|
+
require 'tic_tac_toes/core/move_strategies/medium_ai'
|
3
|
+
require 'tic_tac_toes/core/player_factory'
|
2
4
|
require 'tic_tac_toes/test_board_generator'
|
3
5
|
|
4
6
|
describe TicTacToes::Core::GameState do
|
5
|
-
describe '
|
6
|
-
it "records
|
7
|
+
describe '#start_game' do
|
8
|
+
it "records the board size" do
|
7
9
|
size = 5
|
8
10
|
board = double(size: size)
|
11
|
+
player = TicTacToes::Core::PlayerFactory.new('unused_io').generate_player('x', :medium)
|
12
|
+
players = [player]
|
9
13
|
history = double
|
10
14
|
|
15
|
+
allow(history).to receive(:record_difficulty)
|
11
16
|
expect(history).to receive(:record_board_size).with(size)
|
12
|
-
TicTacToes::Core::GameState.new(board,
|
17
|
+
TicTacToes::Core::GameState.new(board, players, history).start_game
|
18
|
+
end
|
19
|
+
|
20
|
+
it "records the AI difficulty" do
|
21
|
+
board = double(size: true)
|
22
|
+
computer_player = TicTacToes::Core::PlayerFactory.new('unused_io').generate_player('x', :medium)
|
23
|
+
human_player = TicTacToes::Core::PlayerFactory.new('unused_io').generate_player('o', :human)
|
24
|
+
players = [computer_player, human_player]
|
25
|
+
ai = TicTacToes::Core::MoveStrategies::MediumAI
|
26
|
+
history = double
|
27
|
+
|
28
|
+
allow(history).to receive(:record_board_size)
|
29
|
+
expect(history).to receive(:record_difficulty).with(ai)
|
30
|
+
TicTacToes::Core::GameState.new(board, players, history).start_game
|
13
31
|
end
|
14
32
|
end
|
15
33
|
|
@@ -91,14 +109,14 @@ describe TicTacToes::Core::GameState do
|
|
91
109
|
end
|
92
110
|
end
|
93
111
|
|
94
|
-
describe '#
|
112
|
+
describe '#end_game' do
|
95
113
|
it 'records the winner' do
|
96
114
|
winning_player = double
|
97
115
|
history = double(record_board_size: true, persist: true)
|
98
116
|
game_state = TicTacToes::Core::GameState.new('board', 'players', history)
|
99
117
|
|
100
118
|
expect(history).to receive(:record_winner).with(winning_player)
|
101
|
-
game_state.
|
119
|
+
game_state.end_game(winning_player)
|
102
120
|
end
|
103
121
|
|
104
122
|
it 'persists its history' do
|
@@ -107,7 +125,7 @@ describe TicTacToes::Core::GameState do
|
|
107
125
|
game_state = TicTacToes::Core::GameState.new('board', 'players', history)
|
108
126
|
|
109
127
|
expect(history).to receive(:persist)
|
110
|
-
game_state.
|
128
|
+
game_state.end_game(winning_player)
|
111
129
|
end
|
112
130
|
end
|
113
131
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'tic_tac_toes/core/history'
|
2
|
+
require 'tic_tac_toes/core/move_strategies/medium_ai'
|
2
3
|
|
3
4
|
describe TicTacToes::Core::History do
|
4
5
|
let(:database_wrapper) { double("database wrapper", :record_game_history => true) }
|
@@ -13,6 +14,15 @@ describe TicTacToes::Core::History do
|
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
17
|
+
describe '#record_difficulty' do
|
18
|
+
it "records the passed difficulty" do
|
19
|
+
difficulty = TicTacToes::Core::MoveStrategies::MediumAI
|
20
|
+
|
21
|
+
history.record_difficulty(difficulty)
|
22
|
+
expect(history.difficulty).to eq('Medium AI')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
16
26
|
describe '#record_move' do
|
17
27
|
it "records the passed token and space" do
|
18
28
|
move = ["X", 0]
|
@@ -121,7 +121,7 @@ describe TicTacToes::Core::IO do
|
|
121
121
|
|
122
122
|
describe '#game_over_notification' do
|
123
123
|
it "displays a game over message with the name of the winner" do
|
124
|
-
winner =
|
124
|
+
winner = 'X'
|
125
125
|
game_over_message = strings.game_over_notification(winner)
|
126
126
|
|
127
127
|
expect(prompt).to receive(:display).with(game_over_message)
|
@@ -4,8 +4,20 @@ require 'tic_tac_toes/core/move_strategies/easy_ai'
|
|
4
4
|
require 'tic_tac_toes/core/player_factory'
|
5
5
|
|
6
6
|
describe TicTacToes::Core::MoveStrategies::EasyAI do
|
7
|
+
describe '#type' do
|
8
|
+
it 'returns :computer' do
|
9
|
+
expect(TicTacToes::Core::MoveStrategies::EasyAI.type).to eq(:computer)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#ai_type' do
|
14
|
+
it "returns 'EASY_AI'" do
|
15
|
+
expect(TicTacToes::Core::MoveStrategies::EasyAI.ai_type).to eq('EASY_AI')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
7
19
|
describe '#move' do
|
8
|
-
it
|
20
|
+
it 'returns a randomly-selected valid move' do
|
9
21
|
player_factory = TicTacToes::Core::PlayerFactory.new('unused_io')
|
10
22
|
x = player_factory.generate_player('x', TicTacToes::Core::PlayerFactory::HUMAN)
|
11
23
|
o = player_factory.generate_player('o', TicTacToes::Core::PlayerFactory::EASY_AI)
|
@@ -15,6 +15,18 @@ describe TicTacToes::Core::MoveStrategies::HardAI do
|
|
15
15
|
let(:players) { [o, x] }
|
16
16
|
let(:history) { TicTacToes::UI::NullHistory.new }
|
17
17
|
|
18
|
+
describe '#type' do
|
19
|
+
it 'returns :computer' do
|
20
|
+
expect(TicTacToes::Core::MoveStrategies::HardAI.type).to eq(:computer)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#ai_type' do
|
25
|
+
it "returns 'HARD_AI'" do
|
26
|
+
expect(TicTacToes::Core::MoveStrategies::HardAI.ai_type).to eq('HARD_AI')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
18
30
|
describe '#move' do
|
19
31
|
it 'returns the best move' do
|
20
32
|
board = TicTacToes::TestBoardGenerator.generate([x, nil, nil,
|
@@ -1,6 +1,12 @@
|
|
1
1
|
require 'tic_tac_toes/core/move_strategies/human'
|
2
2
|
|
3
3
|
describe TicTacToes::Core::MoveStrategies::Human do
|
4
|
+
describe '#type' do
|
5
|
+
it 'returns :human' do
|
6
|
+
expect(TicTacToes::Core::MoveStrategies::Human.new('unused_io').type).to eq(:human)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
4
10
|
describe '#move' do
|
5
11
|
let(:io) { double('io', solicit_input: 0, move_solicitation: true, not_an_integer_error: true) }
|
6
12
|
let(:human) { TicTacToes::Core::MoveStrategies::Human.new(io) }
|
@@ -4,6 +4,18 @@ require 'tic_tac_toes/core/move_strategies/medium_ai'
|
|
4
4
|
require 'tic_tac_toes/core/player_factory'
|
5
5
|
|
6
6
|
describe TicTacToes::Core::MoveStrategies::MediumAI do
|
7
|
+
describe '#type' do
|
8
|
+
it 'returns :computer' do
|
9
|
+
expect(TicTacToes::Core::MoveStrategies::MediumAI.type).to eq(:computer)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#ai_type' do
|
14
|
+
it "returns 'MEDIUM_AI'" do
|
15
|
+
expect(TicTacToes::Core::MoveStrategies::MediumAI.ai_type).to eq('MEDIUM_AI')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
7
19
|
describe '#move' do
|
8
20
|
it "returns a valid move (based on either EasyAI or HardAI)" do
|
9
21
|
player_factory = TicTacToes::Core::PlayerFactory.new('unused_io')
|
@@ -7,10 +7,12 @@ describe TicTacToes::Database::PGWrapper do
|
|
7
7
|
let(:pg_wrapper) { TicTacToes::Database::PGWrapper.new(database) }
|
8
8
|
let(:history1) { double("history 1",
|
9
9
|
:board_size => 9,
|
10
|
+
:difficulty => 'Medium AI',
|
10
11
|
:moves => [["X", 1], ["O", 4]],
|
11
12
|
:winner => "X") }
|
12
13
|
let(:history2) { double("history 2",
|
13
14
|
:board_size => 16,
|
15
|
+
:difficulty => 'Easy AI',
|
14
16
|
:moves => [["&", 14]],
|
15
17
|
:winner => "*") }
|
16
18
|
|
@@ -19,6 +21,7 @@ describe TicTacToes::Database::PGWrapper do
|
|
19
21
|
connection.exec("CREATE TABLE games (
|
20
22
|
id serial primary key,
|
21
23
|
board_size integer,
|
24
|
+
difficulty varchar,
|
22
25
|
winner varchar)")
|
23
26
|
connection.exec("CREATE TABLE moves (
|
24
27
|
game integer REFERENCES games (id),
|
@@ -34,6 +37,7 @@ describe TicTacToes::Database::PGWrapper do
|
|
34
37
|
history_from_database = pg_wrapper.read_game_histories.first
|
35
38
|
|
36
39
|
expect(history_from_database.board_size).to eq(9)
|
40
|
+
expect(history_from_database.difficulty).to eq('Medium AI')
|
37
41
|
expect(history_from_database.moves[0]).to eq(["X", 1])
|
38
42
|
expect(history_from_database.moves[1]).to eq(["O", 4])
|
39
43
|
expect(history_from_database.winner).to eq("X")
|
@@ -44,13 +44,13 @@ describe TicTacToes::UI::Serializer do
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
describe '#
|
47
|
+
describe '#ai_type_from_game_state' do
|
48
48
|
it 'returns the type of a game state’s computer player' do
|
49
49
|
move_strategy = TicTacToes::Core::PlayerFactory::AIS.fetch(TicTacToes::Core::PlayerFactory::EASY_AI)
|
50
50
|
computer_player = double(move_strategy: move_strategy)
|
51
51
|
players = [computer_player]
|
52
52
|
game_state = double(players: players)
|
53
|
-
expect(TicTacToes::UI::Serializer.
|
53
|
+
expect(TicTacToes::UI::Serializer.ai_type_from_game_state(game_state)).to eq('EASY_AI')
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tic_tac_toes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Spatafora
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-08-
|
11
|
+
date: 2014-08-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -86,6 +86,7 @@ files:
|
|
86
86
|
- bin/destroy_ttt_databases
|
87
87
|
- bin/set_up_ttt_databases
|
88
88
|
- bin/tic_tac_toes
|
89
|
+
- lib/tic_tac_toes/command_line/history_reader.rb
|
89
90
|
- lib/tic_tac_toes/command_line/menu.rb
|
90
91
|
- lib/tic_tac_toes/command_line/prompt.rb
|
91
92
|
- lib/tic_tac_toes/command_line/runner.rb
|
@@ -97,6 +98,7 @@ files:
|
|
97
98
|
- lib/tic_tac_toes/core/move_strategies/hard_ai.rb
|
98
99
|
- lib/tic_tac_toes/core/move_strategies/human.rb
|
99
100
|
- lib/tic_tac_toes/core/move_strategies/medium_ai.rb
|
101
|
+
- lib/tic_tac_toes/core/move_strategies/types.rb
|
100
102
|
- lib/tic_tac_toes/core/player.rb
|
101
103
|
- lib/tic_tac_toes/core/player_factory.rb
|
102
104
|
- lib/tic_tac_toes/core/rules.rb
|
@@ -107,8 +109,8 @@ files:
|
|
107
109
|
- lib/tic_tac_toes/ui/adapter.rb
|
108
110
|
- lib/tic_tac_toes/ui/serializer.rb
|
109
111
|
- lib/tic_tac_toes/version.rb
|
112
|
+
- spec/tic_tac_toes/command_line/history_reader_spec.rb
|
110
113
|
- spec/tic_tac_toes/command_line/menu_spec.rb
|
111
|
-
- spec/tic_tac_toes/command_line/runner_spec.rb
|
112
114
|
- spec/tic_tac_toes/core/board_spec.rb
|
113
115
|
- spec/tic_tac_toes/core/game_state_spec.rb
|
114
116
|
- spec/tic_tac_toes/core/history_spec.rb
|
@@ -151,8 +153,8 @@ signing_key:
|
|
151
153
|
specification_version: 4
|
152
154
|
summary: The game Tic-tac-toe, featuring an unbeatable AI
|
153
155
|
test_files:
|
156
|
+
- spec/tic_tac_toes/command_line/history_reader_spec.rb
|
154
157
|
- spec/tic_tac_toes/command_line/menu_spec.rb
|
155
|
-
- spec/tic_tac_toes/command_line/runner_spec.rb
|
156
158
|
- spec/tic_tac_toes/core/board_spec.rb
|
157
159
|
- spec/tic_tac_toes/core/game_state_spec.rb
|
158
160
|
- spec/tic_tac_toes/core/history_spec.rb
|