tic_tac_toes 0.0.8 → 0.0.9
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/core/move_strategies/hard_ai.rb +5 -0
- data/lib/tic_tac_toes/ui/adapter.rb +20 -76
- data/lib/tic_tac_toes/ui/serializer.rb +75 -0
- data/lib/tic_tac_toes/version.rb +1 -1
- data/spec/tic_tac_toes/core/move_strategies/hard_ai_spec.rb +8 -0
- data/spec/tic_tac_toes/ui/adapter_spec.rb +45 -48
- data/spec/tic_tac_toes/ui/serializer_spec.rb +43 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 919ce75f7f8ad28d261cef9d2a9c7dc1cb0fdad7
|
4
|
+
data.tar.gz: 676c42fa2f8acb3c7dc03d989ab40febdd9958ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e94d802c318a795d6272a5341a2183248cf355109abf6022ce3fd725c2080987028bc1037fb3134fc1e31f321468b93c21e66e4ea3d663c98cd45a69164efef
|
7
|
+
data.tar.gz: 7bd562a193cde805efb2d9ee5c12f4dc10b4e9fa78b6f1ccc622d1e4cc1c7b1438f5bf3adf523ee41ddab88362fdee97301c2f6c114ac40096fbbad4b7600342
|
data/Gemfile.lock
CHANGED
@@ -5,6 +5,7 @@ module TicTacToes
|
|
5
5
|
module MoveStrategies
|
6
6
|
module HardAI
|
7
7
|
def self.move(board, players)
|
8
|
+
return 0 if nine_board_first_move?(board)
|
8
9
|
return second_move(board) if nine_board_second_move?(board)
|
9
10
|
|
10
11
|
open_spaces = Hash[board.open_spaces.map { |space| [space, nil] }]
|
@@ -60,6 +61,10 @@ module TicTacToes
|
|
60
61
|
end
|
61
62
|
end
|
62
63
|
|
64
|
+
def self.nine_board_first_move?(board)
|
65
|
+
board.size == 9 && board.open_spaces.count == 9
|
66
|
+
end
|
67
|
+
|
63
68
|
def self.nine_board_second_move?(board)
|
64
69
|
board.size == 9 && board.open_spaces.count == 8
|
65
70
|
end
|
@@ -1,95 +1,39 @@
|
|
1
|
-
require 'tic_tac_toes/core/board'
|
2
|
-
require 'tic_tac_toes/core/game_state'
|
3
|
-
require 'tic_tac_toes/core/player_factory'
|
4
|
-
require 'tic_tac_toes/core/rules'
|
5
|
-
|
6
1
|
module TicTacToes
|
7
2
|
module UI
|
8
3
|
module Adapter
|
9
|
-
def self.
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
def self.make_move(board_structure, move, listener)
|
15
|
-
move = move.to_i
|
16
|
-
game_state = game_state_from_board_structure(board_structure)
|
17
|
-
|
18
|
-
human_player = game_state.players.first
|
19
|
-
game_state.board.place(human_player, move)
|
4
|
+
def self.make_move(game_state, move, listener)
|
5
|
+
unless move.nil?
|
6
|
+
move = move.to_i
|
7
|
+
game_state.board.place(game_state.current_player, move)
|
8
|
+
end
|
20
9
|
|
21
|
-
if
|
22
|
-
|
10
|
+
if game_state.game_over?
|
11
|
+
tell_listener_game_is_over(game_state, listener)
|
12
|
+
return
|
23
13
|
end
|
24
14
|
|
25
15
|
game_state.turn_over(move)
|
16
|
+
game_state.current_player.place_and_return_move(game_state.board, game_state.players)
|
26
17
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
if Core::Rules.game_over?(game_state.board, game_state.players)
|
31
|
-
return listener.game_is_over(game_state_to_board_structure(game_state), "Game over")
|
18
|
+
if game_state.game_over?
|
19
|
+
tell_listener_game_is_over(game_state, listener)
|
20
|
+
return
|
32
21
|
end
|
33
22
|
|
34
|
-
listener.
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.game_state_from_board_structure(board_structure)
|
38
|
-
player_factory = Core::PlayerFactory.new('unused_io')
|
39
|
-
human_player = player_factory.generate_human_player('X')
|
40
|
-
computer_player = player_factory.generate_computer_player('O', :hard)
|
41
|
-
players = [human_player, computer_player]
|
42
|
-
|
43
|
-
board_structure_with_players = replace_tokens_with_players(board_structure, human_player, computer_player)
|
44
|
-
board = board_from_structure(board_structure_with_players)
|
45
|
-
|
46
|
-
Core::GameState.new(board, players, NullHistory.new)
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.game_state_to_board_structure(game_state)
|
50
|
-
structure_with_players = game_state.board.spaces
|
51
|
-
|
52
|
-
replace_players_with_tokens(structure_with_players)
|
23
|
+
listener.moves_were_made(game_state)
|
53
24
|
end
|
54
25
|
|
55
26
|
private
|
56
27
|
|
57
|
-
def self.
|
58
|
-
|
59
|
-
case space
|
60
|
-
when 'X'
|
61
|
-
human_player
|
62
|
-
when 'O'
|
63
|
-
computer_player
|
64
|
-
else
|
65
|
-
nil
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def self.replace_players_with_tokens(board_structure)
|
71
|
-
board_structure.map { |space| space.token unless space.nil? }
|
72
|
-
end
|
73
|
-
|
74
|
-
def self.board_from_structure(board_structure)
|
75
|
-
row_size = Math.sqrt(board_structure.count).to_i
|
76
|
-
board = Core::Board.new(row_size: row_size)
|
28
|
+
def self.tell_listener_game_is_over(game_state, listener)
|
29
|
+
winning_token = game_state.determine_winner
|
77
30
|
|
78
|
-
|
79
|
-
|
31
|
+
case winning_token
|
32
|
+
when nil
|
33
|
+
listener.game_ended_in_draw(game_state)
|
34
|
+
else
|
35
|
+
listener.game_ended_in_winner(game_state, winning_token)
|
80
36
|
end
|
81
|
-
|
82
|
-
board
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
class NullHistory
|
87
|
-
def record_board_size(size)
|
88
|
-
nil
|
89
|
-
end
|
90
|
-
|
91
|
-
def record_move(move)
|
92
|
-
nil
|
93
37
|
end
|
94
38
|
end
|
95
39
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'tic_tac_toes/core/board'
|
2
|
+
require 'tic_tac_toes/core/game_state'
|
3
|
+
require 'tic_tac_toes/core/player_factory'
|
4
|
+
|
5
|
+
module TicTacToes
|
6
|
+
module UI
|
7
|
+
module Serializer
|
8
|
+
X = 'X'
|
9
|
+
O = 'O'
|
10
|
+
|
11
|
+
def self.new_board_structure
|
12
|
+
board = Core::Board.new
|
13
|
+
board.spaces
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.game_state_from_board_structure(board_structure)
|
17
|
+
player_factory = Core::PlayerFactory.new('unused_io')
|
18
|
+
human_player = player_factory.generate_human_player(X)
|
19
|
+
computer_player = player_factory.generate_computer_player(O, :hard)
|
20
|
+
players = [human_player, computer_player]
|
21
|
+
|
22
|
+
board_structure_with_players = replace_tokens_with_players(board_structure, human_player, computer_player)
|
23
|
+
board = board_from_structure(board_structure_with_players)
|
24
|
+
|
25
|
+
Core::GameState.new(board, players, NullHistory.new)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.game_state_to_board_structure(game_state)
|
29
|
+
structure_with_players = game_state.board.spaces
|
30
|
+
|
31
|
+
replace_players_with_tokens(structure_with_players)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def self.replace_tokens_with_players(board_structure, human_player, computer_player)
|
37
|
+
board_structure.map do |space|
|
38
|
+
case space
|
39
|
+
when X
|
40
|
+
human_player
|
41
|
+
when O
|
42
|
+
computer_player
|
43
|
+
else
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.replace_players_with_tokens(board_structure)
|
50
|
+
board_structure.map { |space| space.token unless space.nil? }
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.board_from_structure(board_structure)
|
54
|
+
row_size = Math.sqrt(board_structure.count).to_i
|
55
|
+
board = Core::Board.new(row_size: row_size)
|
56
|
+
|
57
|
+
board_structure.each_with_index do |player, index|
|
58
|
+
board.place(player, index)
|
59
|
+
end
|
60
|
+
|
61
|
+
board
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class NullHistory
|
66
|
+
def record_board_size(size)
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
|
70
|
+
def record_move(move)
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/tic_tac_toes/version.rb
CHANGED
@@ -20,6 +20,14 @@ describe TicTacToes::Core::MoveStrategies::HardAI do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
context "when playing on a 3x3 board" do
|
23
|
+
it 'returns 0 when making the first move' do
|
24
|
+
board = TicTacToes::TestBoardGenerator.generate([nil, nil, nil,
|
25
|
+
nil, nil, nil,
|
26
|
+
nil, nil, nil])
|
27
|
+
|
28
|
+
expect(hard_ai.move(board, players)).to eq(0)
|
29
|
+
end
|
30
|
+
|
23
31
|
it "returns 4 when the opponent’s first move was a corner" do
|
24
32
|
board = TicTacToes::TestBoardGenerator.generate([nil, nil, nil,
|
25
33
|
nil, nil, nil,
|
@@ -1,72 +1,69 @@
|
|
1
|
-
require 'tic_tac_toes/core/board'
|
2
1
|
require 'tic_tac_toes/core/game_state'
|
3
2
|
require 'tic_tac_toes/core/player_factory'
|
3
|
+
require 'tic_tac_toes/test_board_generator'
|
4
4
|
require 'tic_tac_toes/ui/adapter'
|
5
5
|
|
6
6
|
describe TicTacToes::UI::Adapter do
|
7
|
-
describe '#new_board_structure' do
|
8
|
-
it 'returns a new board structure' do
|
9
|
-
new_board_structure = [nil, nil, nil, nil, nil, nil, nil, nil, nil]
|
10
|
-
expect(TicTacToes::UI::Adapter.new_board_structure).to eq(new_board_structure)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
7
|
describe '#make_move' do
|
8
|
+
let(:history) { double(record_board_size: true,
|
9
|
+
record_move: true) }
|
10
|
+
player_factory = TicTacToes::Core::PlayerFactory.new('unused_io')
|
11
|
+
let(:x) { player_factory.generate_human_player('x') }
|
12
|
+
let(:o) { player_factory.generate_computer_player('o', :hard) }
|
13
|
+
let(:players) { [x, o] }
|
14
|
+
|
15
15
|
context 'when the game is still in progress' do
|
16
|
-
it 'sends its listener
|
17
|
-
|
18
|
-
|
16
|
+
it 'sends its listener #moves_were_made with the updated game state' do
|
17
|
+
board = TicTacToes::TestBoardGenerator.generate([ x, nil, nil,
|
18
|
+
nil, o, nil,
|
19
|
+
nil, nil, nil])
|
20
|
+
game_state = TicTacToes::Core::GameState.new(board, players, history)
|
21
|
+
move = '2'
|
19
22
|
listener = double
|
20
23
|
|
21
|
-
|
24
|
+
allow(listener).to receive(:moves_were_made)
|
25
|
+
TicTacToes::UI::Adapter.make_move(game_state, move, listener)
|
22
26
|
|
23
|
-
|
24
|
-
|
27
|
+
first_move, second_move = 2, 1
|
28
|
+
game_state.board.place(x, first_move)
|
29
|
+
game_state.board.place(o, second_move)
|
30
|
+
expect(listener).to have_received(:moves_were_made).with(game_state)
|
25
31
|
end
|
26
32
|
end
|
27
33
|
|
28
|
-
context 'when the game has ended' do
|
29
|
-
it 'sends its listener
|
30
|
-
|
31
|
-
|
34
|
+
context 'when the game has ended with a winner' do
|
35
|
+
it 'sends its listener #game_ended_in_winner with the updated game state and the winning token' do
|
36
|
+
board = TicTacToes::TestBoardGenerator.generate([ x, x, nil,
|
37
|
+
nil, nil, nil,
|
38
|
+
nil, nil, nil])
|
39
|
+
game_state = TicTacToes::Core::GameState.new(board, players, history)
|
40
|
+
move = '2'
|
32
41
|
listener = double
|
42
|
+
winning_token = 'x'
|
33
43
|
|
34
|
-
|
35
|
-
|
44
|
+
allow(listener).to receive(:game_ended_in_winner)
|
45
|
+
TicTacToes::UI::Adapter.make_move(game_state, move, listener)
|
36
46
|
|
37
|
-
|
38
|
-
|
47
|
+
game_state.board.place(x, 2)
|
48
|
+
expect(listener).to have_received(:game_ended_in_winner).with(game_state, winning_token)
|
39
49
|
end
|
40
50
|
end
|
41
|
-
end
|
42
|
-
|
43
|
-
describe '#game_state_from_board_structure' do
|
44
|
-
it 'returns a game state object based on a board structure' do
|
45
|
-
board_structure = [nil, nil, nil, nil, "X", nil, nil, nil, nil]
|
46
51
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
end
|
56
|
-
end
|
52
|
+
context 'when the game has ended in a draw' do
|
53
|
+
it 'sends its listener #game_ended_in_draw with the updated game state' do
|
54
|
+
board = TicTacToes::TestBoardGenerator.generate([x, x, o,
|
55
|
+
o, o, x,
|
56
|
+
x, o, nil])
|
57
|
+
game_state = TicTacToes::Core::GameState.new(board, players, history)
|
58
|
+
move = '8'
|
59
|
+
listener = double
|
57
60
|
|
58
|
-
|
59
|
-
|
60
|
-
player_factory = TicTacToes::Core::PlayerFactory.new('unused_io')
|
61
|
-
first_player = player_factory.generate_human_player('X')
|
62
|
-
second_player = player_factory.generate_computer_player('O', :hard)
|
63
|
-
players = [first_player, second_player]
|
64
|
-
board = TicTacToes::Core::Board.new
|
65
|
-
board.place(first_player, 4)
|
61
|
+
allow(listener).to receive(:game_ended_in_draw)
|
62
|
+
TicTacToes::UI::Adapter.make_move(game_state, move, listener)
|
66
63
|
|
67
|
-
|
68
|
-
|
69
|
-
|
64
|
+
game_state.board.place(x, 8)
|
65
|
+
expect(listener).to have_received(:game_ended_in_draw).with(game_state)
|
66
|
+
end
|
70
67
|
end
|
71
68
|
end
|
72
69
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'tic_tac_toes/core/board'
|
2
|
+
require 'tic_tac_toes/core/game_state'
|
3
|
+
require 'tic_tac_toes/core/player_factory'
|
4
|
+
require 'tic_tac_toes/ui/serializer'
|
5
|
+
|
6
|
+
describe TicTacToes::UI::Serializer do
|
7
|
+
describe '#new_board_structure' do
|
8
|
+
it 'returns a new board structure' do
|
9
|
+
new_board_structure = [nil, nil, nil, nil, nil, nil, nil, nil, nil]
|
10
|
+
expect(TicTacToes::UI::Serializer.new_board_structure).to eq(new_board_structure)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#game_state_from_board_structure' do
|
15
|
+
it 'returns a game state object based on a board structure' do
|
16
|
+
board_structure = [nil, nil, nil, nil, 'X', nil, nil, nil, nil]
|
17
|
+
|
18
|
+
game_state = TicTacToes::UI::Serializer.game_state_from_board_structure(board_structure)
|
19
|
+
middle_space = game_state.board.space(4)
|
20
|
+
first_player = game_state.players.first
|
21
|
+
second_player = game_state.players.last
|
22
|
+
|
23
|
+
expect(middle_space.token).to eq(TicTacToes::UI::Serializer::X)
|
24
|
+
expect(first_player.token).to eq(TicTacToes::UI::Serializer::X)
|
25
|
+
expect(second_player.token).to eq(TicTacToes::UI::Serializer::O)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#game_state_to_board_structure' do
|
30
|
+
it 'returns a board structure based on a game state object' do
|
31
|
+
player_factory = TicTacToes::Core::PlayerFactory.new('unused_io')
|
32
|
+
first_player = player_factory.generate_human_player(TicTacToes::UI::Serializer::X)
|
33
|
+
second_player = player_factory.generate_computer_player(TicTacToes::UI::Serializer::O, :hard)
|
34
|
+
players = [first_player, second_player]
|
35
|
+
board = TicTacToes::Core::Board.new
|
36
|
+
board.place(first_player, 4)
|
37
|
+
|
38
|
+
game_state = TicTacToes::Core::GameState.new(board, players, TicTacToes::UI::NullHistory.new)
|
39
|
+
board_structure = [nil, nil, nil, nil, 'X', nil, nil, nil, nil]
|
40
|
+
expect(TicTacToes::UI::Serializer.game_state_to_board_structure(game_state)).to eq(board_structure)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
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.0.
|
4
|
+
version: 0.0.9
|
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-07-
|
11
|
+
date: 2014-07-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|