tic_tac_toes 0.1.1 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1e7b4f6653858ee05ee85a0ad10f519879bed750
4
- data.tar.gz: e5aaea09afc5342b96fb823881ba26ef691f00af
3
+ metadata.gz: 0e7dac5d68711dc5bafd138607af1f05cb9753c5
4
+ data.tar.gz: 20480d443fcc914f9f844aa40db5a90b4a52300f
5
5
  SHA512:
6
- metadata.gz: 49287beb325485b2b1affb085f082f03804f8c0a9a21bd761ca8bddca64e681fb98be844dac1c6ec0d1f3df58ee96e7e23518b18351c06b021838c5cbf05cb19
7
- data.tar.gz: 0874989c2aaf4f7dd1712266303fbad25c4f911507c158b65d0e1ae72b94605e842366b708485f21f51420cb99823e7bd403f8ada58b58cb947783e377cc310b
6
+ metadata.gz: 6d6b6478a8b3c54643825073c4106336c210f715c119570dbbac80caf89f6cd8a8dbe1b1ad0758557326603e115b4e987aa0792fbe318ebb8680ce30035bc1b7
7
+ data.tar.gz: b3bbd7b5bc6dc32e8fb175bc2d66160e4f8177be37ab301ac9ef1d492b58a5c095e325ef47f66b4f1d10b1fafd7cb7a7451b2ad9eacddb4c4f52a25f0e23afda
data/Gemfile.lock CHANGED
@@ -14,14 +14,14 @@ GEM
14
14
  rspec-core (~> 3.0.0)
15
15
  rspec-expectations (~> 3.0.0)
16
16
  rspec-mocks (~> 3.0.0)
17
- rspec-core (3.0.3)
17
+ rspec-core (3.0.4)
18
18
  rspec-support (~> 3.0.0)
19
- rspec-expectations (3.0.3)
19
+ rspec-expectations (3.0.4)
20
20
  diff-lcs (>= 1.2.0, < 2.0)
21
21
  rspec-support (~> 3.0.0)
22
- rspec-mocks (3.0.3)
22
+ rspec-mocks (3.0.4)
23
23
  rspec-support (~> 3.0.0)
24
- rspec-support (3.0.3)
24
+ rspec-support (3.0.4)
25
25
 
26
26
  PLATFORMS
27
27
  ruby
@@ -4,7 +4,7 @@ module TicTacToes
4
4
  module Core
5
5
  module MoveStrategies
6
6
  module HardAI
7
- ALPHA, BETA = -1, 1
7
+ ALPHA, BETA, DEPTH = -100, 100, 0
8
8
 
9
9
  def self.move(game_state)
10
10
  board = game_state.board
@@ -15,7 +15,7 @@ module TicTacToes
15
15
  open_spaces = Hash[board.open_spaces.map { |space| [space, nil] }]
16
16
 
17
17
  open_spaces.each do |space, score|
18
- score = minimax(generate_game_state(space, game_state), :min, ALPHA, BETA)
18
+ score = minimax(generate_game_state(space, game_state), :min, ALPHA, BETA, DEPTH)
19
19
  open_spaces[space] = score
20
20
  end
21
21
 
@@ -25,18 +25,18 @@ module TicTacToes
25
25
 
26
26
  private
27
27
 
28
- def self.minimax(game_state, current_player, alpha, beta)
29
- return score(game_state) if game_state.game_over?
28
+ def self.minimax(game_state, current_player, alpha, beta, depth)
29
+ return score(game_state, depth) if game_state.game_over?
30
30
 
31
31
  if current_player == :max
32
32
  game_state.board.open_spaces.each do |space|
33
- alpha = [alpha, minimax(generate_game_state(space, game_state), :min, alpha, beta)].max
33
+ alpha = [alpha, minimax(generate_game_state(space, game_state), :min, alpha, beta, depth + 1)].max
34
34
  break if beta <= alpha
35
35
  end
36
36
  alpha
37
37
  elsif current_player == :min
38
38
  game_state.board.open_spaces.each do |space|
39
- beta = [beta, minimax(generate_game_state(space, game_state), :max, alpha, beta)].min
39
+ beta = [beta, minimax(generate_game_state(space, game_state), :max, alpha, beta, depth + 1)].min
40
40
  break if beta <= alpha
41
41
  end
42
42
  beta
@@ -50,14 +50,14 @@ module TicTacToes
50
50
  new_game_state
51
51
  end
52
52
 
53
- def self.score(game_state)
53
+ def self.score(game_state, depth)
54
54
  winner = game_state.determine_winner
55
55
  if winner.nil?
56
56
  0
57
- elsif winner.move_strategy == self
58
- 1
57
+ elsif winner.move_strategy.is_a? Human
58
+ -100
59
59
  else
60
- -1
60
+ 100 - depth
61
61
  end
62
62
  end
63
63
 
@@ -1,3 +1,6 @@
1
+ require 'tic_tac_toes/core/player_factory'
2
+ require 'tic_tac_toes/core/move_strategies/hard_ai'
3
+
1
4
  module TicTacToes
2
5
  module UI
3
6
  module Adapter
@@ -32,6 +35,23 @@ module TicTacToes
32
35
  listener.moves_were_made(game_state)
33
36
  end
34
37
 
38
+ def self.predictions(game_state)
39
+ predictions = []
40
+ (0..8).each do |space|
41
+ next predictions << nil unless game_state.board.space(space).nil?
42
+
43
+ potential_game_state = generate_game_state(game_state, space)
44
+ next predictions << predicted_result(potential_game_state) if potential_game_state.game_over?
45
+
46
+ potential_game_state.turn_over([])
47
+ potential_game_state.place_move(Core::MoveStrategies::HardAI.move(potential_game_state))
48
+ next predictions << predicted_result(potential_game_state) if potential_game_state.game_over?
49
+
50
+ predictions << nil
51
+ end
52
+ predictions
53
+ end
54
+
35
55
  private
36
56
 
37
57
  def self.tell_listener_game_is_over(game_state, listener)
@@ -44,6 +64,25 @@ module TicTacToes
44
64
  listener.game_ended_in_winner(game_state, winning_player.token)
45
65
  end
46
66
  end
67
+
68
+ def self.generate_game_state(game_state, space)
69
+ new_game_state = Marshal.load(Marshal.dump(game_state))
70
+ new_game_state.turn_over([])
71
+ new_game_state.place_move(space)
72
+ new_game_state
73
+ end
74
+
75
+ def self.predicted_result(game_state)
76
+ winner = game_state.determine_winner
77
+
78
+ if winner.nil?
79
+ "tie"
80
+ elsif winner.move_strategy.is_a? Core::MoveStrategies::Human
81
+ "win"
82
+ else
83
+ "loss"
84
+ end
85
+ end
47
86
  end
48
87
  end
49
88
  end
@@ -1,3 +1,3 @@
1
1
  module TicTacToes
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
@@ -1,13 +1,16 @@
1
1
  require 'tic_tac_toes/test_board_generator'
2
2
  require 'tic_tac_toes/core/move_strategies/hard_ai'
3
+ require 'tic_tac_toes/core/move_strategies/human'
3
4
  require 'tic_tac_toes/core/game_state'
4
5
  require 'tic_tac_toes/core/player'
5
6
 
6
7
  describe TicTacToes::Core::MoveStrategies::HardAI do
7
8
  let(:alpha) { TicTacToes::Core::MoveStrategies::HardAI::ALPHA }
8
9
  let(:beta) { TicTacToes::Core::MoveStrategies::HardAI::BETA }
10
+ let(:depth) { TicTacToes::Core::MoveStrategies::HardAI::DEPTH }
9
11
  let(:hard_ai) { TicTacToes::Core::MoveStrategies::HardAI }
10
- let(:x) { TicTacToes::Core::Player.new("human", "x", false, "io") }
12
+ let(:human) { TicTacToes::Core::MoveStrategies::Human.new('unused_io') }
13
+ let(:x) { TicTacToes::Core::Player.new(human, "x", false, "io") }
11
14
  let(:o) { TicTacToes::Core::Player.new(hard_ai, "o", true, "io") }
12
15
  let(:players) { [o, x] }
13
16
  let(:history) { TicTacToes::UI::NullHistory.new }
@@ -69,9 +72,9 @@ describe TicTacToes::Core::MoveStrategies::HardAI do
69
72
  o, o, nil,
70
73
  x, nil, x])
71
74
  game_state = TicTacToes::Core::GameState.new(board, players, history)
72
- win_score = 1
75
+ win_score = 99
73
76
 
74
- expect(hard_ai.minimax(game_state, :max, alpha, beta)).to eql(win_score)
77
+ expect(hard_ai.minimax(game_state, :max, alpha, beta, depth)).to eql(win_score)
75
78
  end
76
79
 
77
80
  it 'returns the correct score for a pre-loss board' do
@@ -79,9 +82,9 @@ describe TicTacToes::Core::MoveStrategies::HardAI do
79
82
  nil, nil, nil,
80
83
  x, nil, x])
81
84
  game_state = TicTacToes::Core::GameState.new(board, players, history)
82
- loss_score = -1
85
+ loss_score = -100
83
86
 
84
- expect(hard_ai.minimax(game_state, :max, alpha, beta)).to eql(loss_score)
87
+ expect(hard_ai.minimax(game_state, :max, alpha, beta, depth)).to eql(loss_score)
85
88
  end
86
89
 
87
90
  it 'returns the correct score for a pre-draw board' do
@@ -91,7 +94,7 @@ describe TicTacToes::Core::MoveStrategies::HardAI do
91
94
  game_state = TicTacToes::Core::GameState.new(board, players, history)
92
95
  draw_score = 0
93
96
 
94
- expect(hard_ai.minimax(game_state, :max, alpha, beta)).to eql(draw_score)
97
+ expect(hard_ai.minimax(game_state, :max, alpha, beta, depth)).to eql(draw_score)
95
98
  end
96
99
  end
97
100
 
@@ -116,9 +119,9 @@ describe TicTacToes::Core::MoveStrategies::HardAI do
116
119
  nil, o, nil,
117
120
  nil, nil, o])
118
121
  game_state = TicTacToes::Core::GameState.new(board, players, history)
119
- win_score = 1
122
+ win_score = 100
120
123
 
121
- expect(hard_ai.score(game_state)).to eq(win_score)
124
+ expect(hard_ai.score(game_state, depth)).to eq(win_score)
122
125
  end
123
126
 
124
127
  it 'returns the correct score when no one has won' do
@@ -128,7 +131,7 @@ describe TicTacToes::Core::MoveStrategies::HardAI do
128
131
  game_state = TicTacToes::Core::GameState.new(board, players, history)
129
132
  draw_score = 0
130
133
 
131
- expect(hard_ai.score(game_state)).to eql(draw_score)
134
+ expect(hard_ai.score(game_state, depth)).to eql(draw_score)
132
135
  end
133
136
 
134
137
  it 'returns the correct score when the opponent has won' do
@@ -136,9 +139,9 @@ describe TicTacToes::Core::MoveStrategies::HardAI do
136
139
  nil, x, nil,
137
140
  nil, nil, x])
138
141
  game_state = TicTacToes::Core::GameState.new(board, players, history)
139
- loss_score = -1
142
+ loss_score = -100
140
143
 
141
- expect(hard_ai.score(game_state)).to eql(loss_score)
144
+ expect(hard_ai.score(game_state, depth)).to eql(loss_score)
142
145
  end
143
146
  end
144
147
  end
@@ -91,4 +91,57 @@ describe TicTacToes::UI::Adapter do
91
91
  end
92
92
  end
93
93
  end
94
+
95
+ describe '#predictions' do
96
+ let(:history) { TicTacToes::UI::NullHistory.new }
97
+
98
+ player_factory = TicTacToes::Core::PlayerFactory.new('unused_io')
99
+ let(:x) { player_factory.generate_player('x', TicTacToes::Core::PlayerFactory::HUMAN) }
100
+ let(:o) { player_factory.generate_player('o', TicTacToes::Core::PlayerFactory::HARD_AI) }
101
+ let(:players) { [o, x] }
102
+
103
+ it 'returns an array indicating which moves will result in a win' do
104
+ board = TicTacToes::TestBoardGenerator.generate([ x, x, nil,
105
+ nil, nil, nil,
106
+ nil, x, x])
107
+ game_state = TicTacToes::Core::GameState.new(board, players, history)
108
+
109
+ expect(TicTacToes::UI::Adapter.predictions(game_state)).to eq([ nil, nil, "win",
110
+ nil, "win", nil,
111
+ "win", nil, nil])
112
+ end
113
+
114
+ it 'returns an array indicating which moves will result in an immediate tie' do
115
+ board = TicTacToes::TestBoardGenerator.generate([x, x, o,
116
+ o, o, x,
117
+ x, o, nil])
118
+ game_state = TicTacToes::Core::GameState.new(board, players, history)
119
+
120
+ expect(TicTacToes::UI::Adapter.predictions(game_state)).to eq([nil, nil, nil,
121
+ nil, nil, nil,
122
+ nil, nil, "tie"])
123
+ end
124
+
125
+ it 'returns an array indicating which moves will result in a tie after the subsequent move' do
126
+ board = TicTacToes::TestBoardGenerator.generate([o, o, x,
127
+ x, x, o,
128
+ o, nil, nil])
129
+ game_state = TicTacToes::Core::GameState.new(board, players, history)
130
+
131
+ expect(TicTacToes::UI::Adapter.predictions(game_state)).to eq([nil, nil, nil,
132
+ nil, nil, nil,
133
+ nil, "tie", "tie"])
134
+ end
135
+
136
+ it 'returns an array indicating which moves will result in a loss after the subsequent move' do
137
+ board = TicTacToes::TestBoardGenerator.generate([ o, x, o,
138
+ x, o, nil,
139
+ nil, nil, x])
140
+ game_state = TicTacToes::Core::GameState.new(board, players, history)
141
+
142
+ expect(TicTacToes::UI::Adapter.predictions(game_state)).to eq([ nil, nil, nil,
143
+ nil, nil, "loss",
144
+ nil, "loss", nil])
145
+ end
146
+ end
94
147
  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.1
4
+ version: 0.1.2
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 00:00:00.000000000 Z
11
+ date: 2014-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler