tic_tac_toes 0.0.2 → 0.0.3

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