tic_tac_toes 0.0.2 → 0.0.3

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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +7 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +2 -0
  5. data/Rakefile +2 -2
  6. data/bin/tic_tac_toes +21 -9
  7. data/lib/command_line/menu.rb +11 -12
  8. data/lib/command_line/{io.rb → prompt.rb} +1 -1
  9. data/lib/command_line/runner.rb +18 -18
  10. data/lib/tic_tac_toes/board_factory.rb +9 -0
  11. data/lib/tic_tac_toes/game_state.rb +27 -0
  12. data/lib/tic_tac_toes/game_state_factory.rb +14 -0
  13. data/lib/tic_tac_toes/history.rb +3 -3
  14. data/lib/tic_tac_toes/io.rb +91 -0
  15. data/lib/tic_tac_toes/move_strategies/easy_ai.rb +11 -0
  16. data/lib/tic_tac_toes/move_strategies/hard_ai.rb +59 -0
  17. data/lib/tic_tac_toes/move_strategies/human.rb +18 -0
  18. data/lib/tic_tac_toes/move_strategies/medium_ai.rb +13 -0
  19. data/lib/tic_tac_toes/player.rb +7 -7
  20. data/lib/tic_tac_toes/player_factory.rb +13 -9
  21. data/lib/tic_tac_toes/rules.rb +1 -1
  22. data/lib/tic_tac_toes/strings.rb +3 -2
  23. data/lib/tic_tac_toes/version.rb +1 -1
  24. data/spec/command_line/menu_spec.rb +40 -44
  25. data/spec/command_line/runner_spec.rb +23 -101
  26. data/spec/database/pg_wrapper_spec.rb +0 -1
  27. data/spec/test_board_generator.rb +15 -0
  28. data/spec/tic_tac_toes/board_factory_spec.rb +13 -0
  29. data/spec/tic_tac_toes/board_spec.rb +20 -25
  30. data/spec/tic_tac_toes/game_state_factory_spec.rb +15 -0
  31. data/spec/tic_tac_toes/game_state_spec.rb +66 -0
  32. data/spec/tic_tac_toes/history_spec.rb +3 -4
  33. data/spec/tic_tac_toes/io_spec.rb +163 -0
  34. data/spec/tic_tac_toes/move_strategies/easy_ai_spec.rb +19 -0
  35. data/spec/tic_tac_toes/move_strategies/hard_ai_spec.rb +95 -0
  36. data/spec/tic_tac_toes/move_strategies/human_spec.rb +31 -0
  37. data/spec/tic_tac_toes/move_strategies/medium_ai_spec.rb +21 -0
  38. data/spec/tic_tac_toes/player_factory_spec.rb +13 -16
  39. data/spec/tic_tac_toes/player_spec.rb +14 -16
  40. data/spec/tic_tac_toes/rules_spec.rb +31 -41
  41. data/spec/tic_tac_toes/strings_spec.rb +0 -1
  42. metadata +32 -19
  43. data/lib/tic_tac_toes/easy_ai.rb +0 -9
  44. data/lib/tic_tac_toes/hard_ai.rb +0 -57
  45. data/lib/tic_tac_toes/io_interface.rb +0 -96
  46. data/lib/tic_tac_toes/medium_ai.rb +0 -11
  47. data/spec/tic_tac_toes/easy_ai_spec.rb +0 -20
  48. data/spec/tic_tac_toes/hard_ai_spec.rb +0 -103
  49. data/spec/tic_tac_toes/io_interface_spec.rb +0 -175
  50. data/spec/tic_tac_toes/medium_ai_spec.rb +0 -22
  51. data/spec/tic_tac_toes/spec_helper.rb +0 -13
  52. /data/lib/{tic_tac_toes/tasks → tasks}/destroy_databases.rake +0 -0
  53. /data/lib/{tic_tac_toes/tasks → tasks}/set_up_databases.rake +0 -0
@@ -0,0 +1,19 @@
1
+ require 'test_board_generator'
2
+ require 'tic_tac_toes/move_strategies/easy_ai'
3
+
4
+ describe TicTacToes::MoveStrategies::EasyAI do
5
+ describe '#move' do
6
+ let(:players) { double("players") }
7
+ let(:easy_ai) { TicTacToes::MoveStrategies::EasyAI }
8
+
9
+ it "returns a randomly-selected valid move" do
10
+ board = TestBoardGenerator.generate([ :O, nil, nil,
11
+ nil, :X, nil,
12
+ nil, :X, nil])
13
+ valid_moves = [1, 2, 3, 5, 6, 8]
14
+
15
+ move = easy_ai.move(board, players)
16
+ expect(valid_moves).to include(move)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,95 @@
1
+ require 'test_board_generator'
2
+ require 'tic_tac_toes/move_strategies/hard_ai'
3
+ require 'tic_tac_toes/player'
4
+
5
+ describe TicTacToes::MoveStrategies::HardAI do
6
+ let(:hard_ai) { TicTacToes::MoveStrategies::HardAI }
7
+ let(:x) { TicTacToes::Player.new("human", "x", false, "io") }
8
+ let(:o) { TicTacToes::Player.new(hard_ai, "o", true, "io") }
9
+ let(:players) { [o, x] }
10
+
11
+
12
+ describe '#move' do
13
+ it "returns the best move" do
14
+ board = TestBoardGenerator.generate([x, nil, nil,
15
+ o, o, nil,
16
+ x, nil, x])
17
+ best_move = 5
18
+
19
+ expect(hard_ai.move(board, players)).to eql(best_move)
20
+ end
21
+ end
22
+
23
+
24
+ describe '#minimax' do
25
+ it "returns the correct score for a pre-win board" do
26
+ board = TestBoardGenerator.generate([x, nil, nil,
27
+ o, o, nil,
28
+ x, nil, x])
29
+ win_score = 1
30
+
31
+ expect(hard_ai.minimax(board, :max, players)).to eql(win_score)
32
+ end
33
+
34
+ it "returns the correct score for a pre-loss board" do
35
+ board = TestBoardGenerator.generate([ o, o, x,
36
+ nil, nil, nil,
37
+ x, nil, x])
38
+ loss_score = -1
39
+
40
+ expect(hard_ai.minimax(board, :max, players)).to eql(loss_score)
41
+ end
42
+
43
+ it "returns the correct score for a pre-draw board" do
44
+ board = TestBoardGenerator.generate([x, x, o,
45
+ o, nil, x,
46
+ x, o, x])
47
+ draw_score = 0
48
+
49
+ expect(hard_ai.minimax(board, :max, players)).to eql(draw_score)
50
+ end
51
+ end
52
+
53
+
54
+ describe '#generate_board' do
55
+ it "returns a board based on a token, a space, and an existing board" do
56
+ token, space = o, 3
57
+ board = TestBoardGenerator.generate([ x, nil, nil,
58
+ nil, o, nil,
59
+ x, nil, nil])
60
+
61
+ new_board = hard_ai.generate_board(token, space, board)
62
+ expect(new_board.space(space)).to eql(token)
63
+ end
64
+ end
65
+
66
+
67
+ describe '#score' do
68
+ it "returns the correct score when HardAI has won" do
69
+ board = TestBoardGenerator.generate([ o, nil, nil,
70
+ nil, o, nil,
71
+ nil, nil, o])
72
+ win_score = 1
73
+
74
+ expect(hard_ai.score(board, players)).to eql(win_score)
75
+ end
76
+
77
+ it "returns the correct score when no one has won" do
78
+ board = TestBoardGenerator.generate([o, o, x,
79
+ x, x, o,
80
+ o, x, o])
81
+ draw_score = 0
82
+
83
+ expect(hard_ai.score(board, players)).to eql(draw_score)
84
+ end
85
+
86
+ it "returns the correct score when the opponent has won" do
87
+ board = TestBoardGenerator.generate([ x, nil, nil,
88
+ nil, x, nil,
89
+ nil, nil, x])
90
+ loss_score = -1
91
+
92
+ expect(hard_ai.score(board, players)).to eql(loss_score)
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,31 @@
1
+ require 'tic_tac_toes/move_strategies/human'
2
+
3
+ describe TicTacToes::MoveStrategies::Human do
4
+ describe '#move' do
5
+ let(:io) { double("io", solicit_input: 0, move_solicitation: true, not_an_integer_error: true) }
6
+ let(:human) { TicTacToes::MoveStrategies::Human.new(io) }
7
+
8
+ it "displays a move solicitation" do
9
+ expect(io).to receive(:move_solicitation)
10
+ human.move("board", "players")
11
+ end
12
+
13
+ context 'when given not-integer-like input' do
14
+ let(:not_integer_like) { "string" }
15
+ let(:integer_like) { "100" }
16
+
17
+ it "displays a not an integer error" do
18
+ allow(io).to receive(:solicit_input).and_return(not_integer_like, integer_like)
19
+
20
+ expect(io).to receive(:not_an_integer_error).once
21
+ human.move("board", "players")
22
+ end
23
+
24
+ it "only returns a move (converted to integer) once it gets integer-like input" do
25
+ allow(io).to receive(:solicit_input).and_return(not_integer_like, integer_like)
26
+
27
+ expect(human.move("board", "players")).to eq(100)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,21 @@
1
+ require 'test_board_generator'
2
+ require 'tic_tac_toes/move_strategies/medium_ai'
3
+
4
+ describe TicTacToes::MoveStrategies::MediumAI do
5
+ let(:medium_ai) { TicTacToes::MoveStrategies::MediumAI }
6
+ let(:x) { TicTacToes::Player.new("human", "x", false, "io") }
7
+ let(:o) { TicTacToes::Player.new(medium_ai, "o", true, "io") }
8
+ let(:players) { [x, o] }
9
+
10
+ describe '#move' do
11
+ it "returns a valid move (based on either EasyAI or HardAI)" do
12
+ board = TestBoardGenerator.generate([ o, o, x,
13
+ nil, x, nil,
14
+ nil, x, nil])
15
+ valid_moves = [3, 5, 6, 8]
16
+
17
+ move = medium_ai.move(board, players)
18
+ expect(valid_moves).to include(move)
19
+ end
20
+ end
21
+ end
@@ -1,33 +1,30 @@
1
- require 'command_line/io'
2
- require 'tic_tac_toes/io_interface'
3
- require 'tic_tac_toes/medium_ai'
1
+ require 'tic_tac_toes/move_strategies/human'
2
+ require 'tic_tac_toes/move_strategies/medium_ai'
4
3
  require 'tic_tac_toes/player_factory'
5
- require 'tic_tac_toes/spec_helper'
6
4
 
7
5
  describe TicTacToes::PlayerFactory do
8
- let(:io) { CommandLine::IO }
9
- let(:io_interface) { TicTacToes::IOInterface.new(io) }
10
- let(:player_factory) { TicTacToes::PlayerFactory.new(io_interface) }
11
-
6
+ let(:player_factory) { TicTacToes::PlayerFactory.new("io") }
12
7
 
13
8
  describe '#generate_human_player' do
14
- it "returns a player with the correct token and decider" do
15
- token = "X"
9
+ it "returns a player with the correct token and move strategy" do
10
+ strategy = TicTacToes::MoveStrategies::Human
11
+ token = 'X'
16
12
 
17
13
  human_player = player_factory.generate_human_player(token)
18
- expect(human_player.decider).to be_a TicTacToes::IOInterface
14
+ expect(human_player.move_strategy).to be_a strategy
19
15
  expect(human_player.token).to eq(token)
20
16
  end
21
17
  end
22
18
 
23
-
24
19
  describe '#generate_computer_player' do
25
- it "returns a player with the correct token and decider when given a valid difficulty" do
26
- token = "O"
20
+ it 'returns a player with the correct token and move strategy' do
21
+ token = 'O'
27
22
  difficulty = :medium
23
+ strategy = TicTacToes::MoveStrategies::MediumAI
28
24
 
29
- computer_player = player_factory.generate_computer_player(token, difficulty)
30
- expect(computer_player.decider).to eql(TicTacToes::MediumAI)
25
+ computer_player = player_factory.generate_computer_player(token,
26
+ difficulty)
27
+ expect(computer_player.move_strategy).to eq(strategy)
31
28
  expect(computer_player.token).to eq(token)
32
29
  end
33
30
  end
@@ -1,34 +1,32 @@
1
1
  require 'tic_tac_toes/board'
2
- require 'tic_tac_toes/io_interface'
3
2
  require 'tic_tac_toes/player'
4
- require 'tic_tac_toes/spec_helper'
5
3
 
6
4
  describe TicTacToes::Player do
7
- let(:board) { TicTacToes::Board.new(row_size: 3) }
8
- let(:io_interface) { double("io_interface", invalid_move_error: true) }
9
- let(:players) { double("players") }
5
+ let(:board) { TicTacToes::Board.new(row_size: 3) }
6
+ let(:io) { double("io", invalid_move_error: true) }
7
+ let(:players) { double("players") }
10
8
 
11
- describe '#make_move' do
12
- let(:decider) { double("decider") }
13
- let(:token) { "X" }
14
- let(:needs_to_think) { false }
9
+ describe '#place_and_return_move' do
10
+ let(:move_strategy) { double("move_strategy") }
11
+ let(:token) { "X" }
12
+ let(:needs_to_think) { false }
15
13
 
16
- let(:player) { TicTacToes::Player.new(decider, token, needs_to_think, io_interface) }
14
+ let(:player) { TicTacToes::Player.new(move_strategy, token, needs_to_think, io) }
17
15
 
18
- it "only returns a move once it receives a valid move" do
16
+ it "only places/returns a move once it receives a valid move" do
19
17
  invalid_space, valid_space = 9, 0
20
- allow(decider).to receive(:make_move).and_return(invalid_space, valid_space)
18
+ allow(move_strategy).to receive(:move).and_return(invalid_space, valid_space)
21
19
 
22
- player.make_move(board, players)
20
+ player.place_and_return_move(board, players)
23
21
  expect(board.space(valid_space)).to eq(player)
24
22
  end
25
23
 
26
24
  it "displays an invalid move error when given an invalid move" do
27
25
  invalid_space, valid_space = 9, 0
28
- allow(decider).to receive(:make_move).and_return(invalid_space, valid_space)
26
+ allow(move_strategy).to receive(:move).and_return(invalid_space, valid_space)
29
27
 
30
- expect(io_interface).to receive(:invalid_move_error)
31
- player.make_move(board, players)
28
+ expect(io).to receive(:invalid_move_error)
29
+ player.place_and_return_move(board, players)
32
30
  end
33
31
  end
34
32
  end
@@ -1,4 +1,4 @@
1
- require 'tic_tac_toes/spec_helper'
1
+ require 'test_board_generator'
2
2
  require 'tic_tac_toes/rules'
3
3
 
4
4
  describe TicTacToes::Rules do
@@ -60,28 +60,25 @@ describe TicTacToes::Rules do
60
60
 
61
61
  describe '#game_over?' do
62
62
  it "returns false if there is not yet a winner and the board is not full" do
63
- structure = [x, x, o,
64
- o, o, nil,
65
- x, o, x]
66
- board = generate_board(structure)
63
+ board = TestBoardGenerator.generate([x, x, o,
64
+ o, o, nil,
65
+ x, o, x])
67
66
 
68
67
  expect(rules.game_over?(board, players)).to be false
69
68
  end
70
69
 
71
70
  it "returns true if any player has won" do
72
- structure = [ x, nil, nil,
73
- nil, x, nil,
74
- nil, nil, x]
75
- board = generate_board(structure)
71
+ board = TestBoardGenerator.generate([ x, nil, nil,
72
+ nil, x, nil,
73
+ nil, nil, x])
76
74
 
77
75
  expect(rules.game_over?(board, players)).to be true
78
76
  end
79
77
 
80
78
  it "returns true if the board is full" do
81
- structure = [x, x, o,
82
- o, o, x,
83
- x, o, x]
84
- board = generate_board(structure)
79
+ board = TestBoardGenerator.generate([x, x, o,
80
+ o, o, x,
81
+ x, o, x])
85
82
 
86
83
  expect(rules.game_over?(board, players)).to be true
87
84
  end
@@ -90,20 +87,18 @@ describe TicTacToes::Rules do
90
87
 
91
88
  describe '#determine_winner' do
92
89
  it "returns the winning token when there is a winner" do
93
- structure = [ o, nil, nil,
94
- nil, o, nil,
95
- nil, nil, o]
96
- board = generate_board(structure)
90
+ board = TestBoardGenerator.generate([ o, nil, nil,
91
+ nil, o, nil,
92
+ nil, nil, o])
97
93
  winning_token = "o"
98
94
 
99
95
  expect(rules.determine_winner(board, players)).to eql(winning_token)
100
96
  end
101
97
 
102
98
  it "returns nil if there is not a winner" do
103
- structure = [x, x, o,
104
- o, o, nil,
105
- x, o, x]
106
- board = generate_board(structure)
99
+ board = TestBoardGenerator.generate([x, x, o,
100
+ o, o, nil,
101
+ x, o, x])
107
102
 
108
103
  expect(rules.determine_winner(board, players)).to be_nil
109
104
  end
@@ -112,46 +107,41 @@ describe TicTacToes::Rules do
112
107
 
113
108
  describe '#win?' do
114
109
  it "returns false if the given token has not won" do
115
- structure = [x, x, o,
116
- o, o, nil,
117
- x, o, x]
118
- board = generate_board(structure)
110
+ board = TestBoardGenerator.generate([x, x, o,
111
+ o, o, nil,
112
+ x, o, x])
119
113
 
120
114
  expect(rules.win?(board, x)).to be false
121
115
  end
122
116
 
123
117
  it "returns true if the given token has achieved a back diagonal win" do
124
- structure = [ x, nil, nil,
125
- nil, x, nil,
126
- nil, nil, x]
127
- board = generate_board(structure)
118
+ board = TestBoardGenerator.generate([ x, nil, nil,
119
+ nil, x, nil,
120
+ nil, nil, x])
128
121
 
129
122
  expect(rules.win?(board, x)).to be true
130
123
  end
131
124
 
132
125
  it "returns true if the given token has achieved a front diagonal win" do
133
- structure = [nil, nil, x,
134
- nil, x, nil,
135
- x, nil, nil]
136
- board = generate_board(structure)
126
+ board = TestBoardGenerator.generate([nil, nil, x,
127
+ nil, x, nil,
128
+ x, nil, nil])
137
129
 
138
130
  expect(rules.win?(board, x)).to be true
139
131
  end
140
132
 
141
133
  it "returns true if the given token has achieved a horizonatal win" do
142
- structure = [nil, nil, nil,
143
- x, x, x,
144
- nil, nil, nil]
145
- board = generate_board(structure)
134
+ board = TestBoardGenerator.generate([nil, nil, nil,
135
+ x, x, x,
136
+ nil, nil, nil])
146
137
 
147
138
  expect(rules.win?(board, x)).to be true
148
139
  end
149
140
 
150
141
  it "returns true if the given token has achieved a vertical win" do
151
- structure = [nil, x, nil,
152
- nil, x, nil,
153
- nil, x, nil]
154
- board = generate_board(structure)
142
+ board = TestBoardGenerator.generate([nil, x, nil,
143
+ nil, x, nil,
144
+ nil, x, nil])
155
145
 
156
146
  expect(rules.win?(board, x)).to be true
157
147
  end
@@ -1,6 +1,5 @@
1
1
  require 'tic_tac_toes/board'
2
2
  require 'tic_tac_toes/rules'
3
- require 'tic_tac_toes/spec_helper'
4
3
  require 'tic_tac_toes/strings'
5
4
 
6
5
  describe TicTacToes::Strings do
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.2
4
+ version: 0.0.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-06-23 00:00:00.000000000 Z
11
+ date: 2014-07-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -77,6 +77,7 @@ extensions: []
77
77
  extra_rdoc_files: []
78
78
  files:
79
79
  - ".gitignore"
80
+ - ".travis.yml"
80
81
  - Gemfile
81
82
  - Gemfile.lock
82
83
  - LICENSE.txt
@@ -85,36 +86,44 @@ files:
85
86
  - bin/destroy_ttt_databases
86
87
  - bin/set_up_ttt_databases
87
88
  - bin/tic_tac_toes
88
- - lib/command_line/io.rb
89
89
  - lib/command_line/menu.rb
90
+ - lib/command_line/prompt.rb
90
91
  - lib/command_line/runner.rb
91
92
  - lib/database/pg_wrapper.rb
93
+ - lib/tasks/destroy_databases.rake
94
+ - lib/tasks/set_up_databases.rake
92
95
  - lib/tic_tac_toes/board.rb
93
- - lib/tic_tac_toes/easy_ai.rb
94
- - lib/tic_tac_toes/hard_ai.rb
96
+ - lib/tic_tac_toes/board_factory.rb
97
+ - lib/tic_tac_toes/game_state.rb
98
+ - lib/tic_tac_toes/game_state_factory.rb
95
99
  - lib/tic_tac_toes/history.rb
96
- - lib/tic_tac_toes/io_interface.rb
97
- - lib/tic_tac_toes/medium_ai.rb
100
+ - lib/tic_tac_toes/io.rb
101
+ - lib/tic_tac_toes/move_strategies/easy_ai.rb
102
+ - lib/tic_tac_toes/move_strategies/hard_ai.rb
103
+ - lib/tic_tac_toes/move_strategies/human.rb
104
+ - lib/tic_tac_toes/move_strategies/medium_ai.rb
98
105
  - lib/tic_tac_toes/player.rb
99
106
  - lib/tic_tac_toes/player_factory.rb
100
107
  - lib/tic_tac_toes/rules.rb
101
108
  - lib/tic_tac_toes/strings.rb
102
- - lib/tic_tac_toes/tasks/destroy_databases.rake
103
- - lib/tic_tac_toes/tasks/set_up_databases.rake
104
109
  - lib/tic_tac_toes/version.rb
105
110
  - spec/command_line/menu_spec.rb
106
111
  - spec/command_line/runner_spec.rb
107
112
  - spec/database/pg_wrapper_spec.rb
113
+ - spec/test_board_generator.rb
114
+ - spec/tic_tac_toes/board_factory_spec.rb
108
115
  - spec/tic_tac_toes/board_spec.rb
109
- - spec/tic_tac_toes/easy_ai_spec.rb
110
- - spec/tic_tac_toes/hard_ai_spec.rb
116
+ - spec/tic_tac_toes/game_state_factory_spec.rb
117
+ - spec/tic_tac_toes/game_state_spec.rb
111
118
  - spec/tic_tac_toes/history_spec.rb
112
- - spec/tic_tac_toes/io_interface_spec.rb
113
- - spec/tic_tac_toes/medium_ai_spec.rb
119
+ - spec/tic_tac_toes/io_spec.rb
120
+ - spec/tic_tac_toes/move_strategies/easy_ai_spec.rb
121
+ - spec/tic_tac_toes/move_strategies/hard_ai_spec.rb
122
+ - spec/tic_tac_toes/move_strategies/human_spec.rb
123
+ - spec/tic_tac_toes/move_strategies/medium_ai_spec.rb
114
124
  - spec/tic_tac_toes/player_factory_spec.rb
115
125
  - spec/tic_tac_toes/player_spec.rb
116
126
  - spec/tic_tac_toes/rules_spec.rb
117
- - spec/tic_tac_toes/spec_helper.rb
118
127
  - spec/tic_tac_toes/strings_spec.rb
119
128
  - tic_tac_toes.gemspec
120
129
  homepage: http://github.com/bspatafora/tic_tac_toes
@@ -145,14 +154,18 @@ test_files:
145
154
  - spec/command_line/menu_spec.rb
146
155
  - spec/command_line/runner_spec.rb
147
156
  - spec/database/pg_wrapper_spec.rb
157
+ - spec/test_board_generator.rb
158
+ - spec/tic_tac_toes/board_factory_spec.rb
148
159
  - spec/tic_tac_toes/board_spec.rb
149
- - spec/tic_tac_toes/easy_ai_spec.rb
150
- - spec/tic_tac_toes/hard_ai_spec.rb
160
+ - spec/tic_tac_toes/game_state_factory_spec.rb
161
+ - spec/tic_tac_toes/game_state_spec.rb
151
162
  - spec/tic_tac_toes/history_spec.rb
152
- - spec/tic_tac_toes/io_interface_spec.rb
153
- - spec/tic_tac_toes/medium_ai_spec.rb
163
+ - spec/tic_tac_toes/io_spec.rb
164
+ - spec/tic_tac_toes/move_strategies/easy_ai_spec.rb
165
+ - spec/tic_tac_toes/move_strategies/hard_ai_spec.rb
166
+ - spec/tic_tac_toes/move_strategies/human_spec.rb
167
+ - spec/tic_tac_toes/move_strategies/medium_ai_spec.rb
154
168
  - spec/tic_tac_toes/player_factory_spec.rb
155
169
  - spec/tic_tac_toes/player_spec.rb
156
170
  - spec/tic_tac_toes/rules_spec.rb
157
- - spec/tic_tac_toes/spec_helper.rb
158
171
  - spec/tic_tac_toes/strings_spec.rb
@@ -1,9 +0,0 @@
1
- require 'tic_tac_toes/board'
2
-
3
- module TicTacToes
4
- module EasyAI
5
- def self.make_move(board, _players)
6
- board.open_spaces.sample
7
- end
8
- end
9
- end
@@ -1,57 +0,0 @@
1
- require 'tic_tac_toes/rules'
2
-
3
- module TicTacToes
4
- module HardAI
5
- def self.make_move(board, players)
6
- open_spaces = Hash[board.open_spaces.map { |space| [space, nil] }]
7
-
8
- open_spaces.each do |space, score|
9
- score = minimax(generate_board(players.first, space, board), :min, players)
10
- open_spaces[space] = score
11
- end
12
-
13
- best_score = open_spaces.values.max
14
- open_spaces.each { |space, score| return space if score == best_score }
15
- end
16
-
17
- def self.minimax(board, current_player, players)
18
- return score(board, players) if Rules.game_over?(board, players)
19
-
20
- if current_player == :max
21
- best_score = -1
22
- board.open_spaces.each do |space|
23
- score = minimax(generate_board(players.first, space, board), :min, players)
24
- best_score = [best_score, score].max
25
- end
26
- best_score
27
-
28
- elsif current_player == :min
29
- best_score = 1
30
- board.open_spaces.each do |space|
31
- score = minimax(generate_board(players.last, space, board), :max, players)
32
- best_score = [best_score, score].min
33
- end
34
- best_score
35
- end
36
- end
37
-
38
- def self.generate_board(player, space, board)
39
- new_board = Marshal.load(Marshal.dump(board))
40
- new_board.place(player, space)
41
- new_board
42
- end
43
-
44
- def self.score(board, players)
45
- own_token, opponent_token = players.first.token, players.last.token
46
-
47
- case Rules.determine_winner(board, players)
48
- when own_token
49
- 1
50
- when opponent_token
51
- -1
52
- else
53
- 0
54
- end
55
- end
56
- end
57
- end
@@ -1,96 +0,0 @@
1
- require 'tic_tac_toes/strings'
2
-
3
- module TicTacToes
4
- class IOInterface
5
- def initialize(io)
6
- @io = io
7
- end
8
-
9
- def make_move(_board, _players)
10
- move_solicitation
11
-
12
- Integer(@io.solicit_input)
13
- rescue ArgumentError
14
- not_an_integer_error
15
- make_move(_board, _players)
16
- end
17
-
18
- def get_row_size
19
- row_size_solicitation
20
-
21
- Integer(@io.solicit_input)
22
- rescue ArgumentError
23
- not_an_integer_error
24
- get_row_size
25
- end
26
-
27
- def get_token(player)
28
- token_solicitation(player)
29
- @io.solicit_input
30
- end
31
-
32
- def get_difficulty
33
- difficulty_solicitation
34
- @io.solicit_input.downcase.to_sym
35
- end
36
-
37
- def draw_board(board)
38
- @io.display(Strings.board(board))
39
- end
40
-
41
- def invalid_row_size_error
42
- @io.display_red(Strings::INVALID_ROW_SIZE)
43
- end
44
-
45
- def invalid_token_error
46
- @io.display_red(Strings::INVALID_TOKEN)
47
- end
48
-
49
- def invalid_difficulty_error
50
- @io.display_red(Strings::INVALID_DIFFICULTY)
51
- end
52
-
53
- def invalid_move_error
54
- @io.display_red(Strings::INVALID_MOVE)
55
- end
56
-
57
- def thinking_notification
58
- @io.display_red(Strings::THINKING)
59
- end
60
-
61
- def game_over_notification(winner)
62
- winner = "Nobody" if winner.nil?
63
- @io.display(Strings.game_over_notification(winner))
64
- end
65
-
66
- def red(message)
67
- @io.red(message)
68
- end
69
-
70
- def blue(message)
71
- @io.blue(message)
72
- end
73
-
74
- private
75
-
76
- def move_solicitation
77
- @io.display(Strings::MOVE_SOLICITATION)
78
- end
79
-
80
- def row_size_solicitation
81
- @io.display(Strings::ROW_SIZE_SOLICITATION)
82
- end
83
-
84
- def token_solicitation(player)
85
- @io.display(Strings.token_solicitation(player))
86
- end
87
-
88
- def difficulty_solicitation
89
- @io.display(Strings::DIFFICULTY_SOLICITATION)
90
- end
91
-
92
- def not_an_integer_error
93
- @io.display_red(Strings::NOT_AN_INTEGER)
94
- end
95
- end
96
- end