tic_tac_toes 0.0.8 → 0.0.9
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/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
|