tic_tac_toes 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|