tic_tac_toes 0.1.1 → 0.1.2

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