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
@@ -1,11 +0,0 @@
1
- require 'tic_tac_toes/easy_ai'
2
- require 'tic_tac_toes/hard_ai'
3
-
4
- module TicTacToes
5
- module MediumAI
6
- def self.make_move(board, players)
7
- ai = [EasyAI, HardAI, HardAI].sample
8
- ai.make_move(board, players)
9
- end
10
- end
11
- end
@@ -1,20 +0,0 @@
1
- require 'tic_tac_toes/spec_helper'
2
- require 'tic_tac_toes/easy_ai'
3
-
4
- describe TicTacToes::EasyAI do
5
- describe '#make_move' do
6
- let(:players) { double("players") }
7
- let(:ai) { TicTacToes::EasyAI }
8
-
9
- it "returns a randomly-selected valid move" do
10
- structure = [ :O, nil, nil,
11
- nil, :X, nil,
12
- nil, :X, nil]
13
- board = generate_board(structure)
14
- valid_moves = [1, 2, 3, 5, 6, 8]
15
-
16
- move = ai.make_move(board, players)
17
- expect(valid_moves).to include(move)
18
- end
19
- end
20
- end
@@ -1,103 +0,0 @@
1
- require 'tic_tac_toes/hard_ai'
2
- require 'tic_tac_toes/player'
3
- require 'tic_tac_toes/spec_helper'
4
-
5
- describe TicTacToes::HardAI do
6
- let(:ai) { TicTacToes::HardAI }
7
- let(:x) { TicTacToes::Player.new("decider", "x", false, "interface") }
8
- let(:o) { TicTacToes::Player.new(ai, "o", true, "interface") }
9
- let(:players) { [o, x] }
10
-
11
-
12
- describe '#make_move' do
13
- it "returns the best move" do
14
- structure = [x, nil, nil,
15
- o, o, nil,
16
- x, nil, x]
17
- board = generate_board(structure)
18
- best_move = 5
19
-
20
- expect(ai.make_move(board, players)).to eql(best_move)
21
- end
22
- end
23
-
24
-
25
- describe '#minimax' do
26
- it "returns the correct score for a pre-win board" do
27
- structure = [x, nil, nil,
28
- o, o, nil,
29
- x, nil, x]
30
- board = generate_board(structure)
31
- win_score = 1
32
-
33
- expect(ai.minimax(board, :max, players)).to eql(win_score)
34
- end
35
-
36
- it "returns the correct score for a pre-loss board" do
37
- structure = [ o, o, x,
38
- nil, nil, nil,
39
- x, nil, x]
40
- board = generate_board(structure)
41
- loss_score = -1
42
-
43
- expect(ai.minimax(board, :max, players)).to eql(loss_score)
44
- end
45
-
46
- it "returns the correct score for a pre-draw board" do
47
- structure = [x, x, o,
48
- o, nil, x,
49
- x, o, x]
50
- board = generate_board(structure)
51
- draw_score = 0
52
-
53
- expect(ai.minimax(board, :max, players)).to eql(draw_score)
54
- end
55
- end
56
-
57
-
58
- describe '#generate_board' do
59
- it "returns a board based on a token, a space, and an existing board" do
60
- token, space = o, 3
61
- structure = [ x, nil, nil,
62
- nil, o, nil,
63
- x, nil, nil]
64
- board = generate_board(structure)
65
-
66
- new_board = ai.generate_board(token, space, board)
67
- expect(new_board.space(space)).to eql(token)
68
- end
69
- end
70
-
71
-
72
- describe '#score' do
73
- it "returns the correct score when HardAI has won" do
74
- structure = [ o, nil, nil,
75
- nil, o, nil,
76
- nil, nil, o]
77
- board = generate_board(structure)
78
- win_score = 1
79
-
80
- expect(ai.score(board, players)).to eql(win_score)
81
- end
82
-
83
- it "returns the correct score when no one has won" do
84
- structure = [o, o, x,
85
- x, x, o,
86
- o, x, o]
87
- board = generate_board(structure)
88
- draw_score = 0
89
-
90
- expect(ai.score(board, players)).to eql(draw_score)
91
- end
92
-
93
- it "returns the correct score when the opponent has won" do
94
- structure = [ x, nil, nil,
95
- nil, x, nil,
96
- nil, nil, x]
97
- board = generate_board(structure)
98
- loss_score = -1
99
-
100
- expect(ai.score(board, players)).to eql(loss_score)
101
- end
102
- end
103
- end
@@ -1,175 +0,0 @@
1
- require 'tic_tac_toes/board'
2
- require 'tic_tac_toes/io_interface'
3
- require 'tic_tac_toes/spec_helper'
4
- require 'tic_tac_toes/strings'
5
-
6
- describe TicTacToes::IOInterface do
7
- let(:strings) { TicTacToes::Strings }
8
- let(:io) { double("io", solicit_input: 0, display: true, display_red: true) }
9
- let(:io_interface) { TicTacToes::IOInterface.new(io) }
10
-
11
-
12
- describe '#make_move' do
13
- it "displays a move solicitation" do
14
- expect(io_interface).to receive(:move_solicitation)
15
- io_interface.make_move("_board", "_players")
16
- end
17
-
18
- context 'when given not-integer-like input' do
19
- let(:not_integer_like) { "string" }
20
- let(:integer_like) { "100" }
21
-
22
- it "displays a not an integer error" do
23
- allow(io).to receive(:solicit_input).and_return(not_integer_like, integer_like)
24
-
25
- expect(io_interface).to receive(:not_an_integer_error).once
26
- io_interface.make_move("_board", "_players")
27
- end
28
-
29
- it "only returns a move (converted to integer) once it gets integer-like input" do
30
- allow(io).to receive(:solicit_input).and_return(not_integer_like, integer_like)
31
-
32
- expect(io_interface.make_move("_board", "_players")).to eq(100)
33
- end
34
- end
35
- end
36
-
37
-
38
- describe '#get_row_size' do
39
- it "displays a row size solicitation" do
40
- expect(io_interface).to receive(:row_size_solicitation)
41
- io_interface.get_row_size
42
- end
43
-
44
- context 'when given not-integer-like input' do
45
- let(:not_integer_like) { "string" }
46
- let(:integer_like) { "100" }
47
-
48
- it "displays a not an integer error" do
49
- allow(io).to receive(:solicit_input).and_return(not_integer_like, integer_like)
50
-
51
- expect(io_interface).to receive(:not_an_integer_error).once
52
- io_interface.get_row_size
53
- end
54
-
55
- it "only returns a row size (converted to integer) once it gets integer-like input" do
56
- allow(io).to receive(:solicit_input).and_return(not_integer_like, integer_like)
57
-
58
- expect(io_interface.get_row_size).to eq(100)
59
- end
60
- end
61
- end
62
-
63
-
64
- describe '#get_token' do
65
- let(:player) { double("player") }
66
-
67
- it "displays a token solicitation with the name of the player whose token is to be set" do
68
- expect(io_interface).to receive(:token_solicitation).with(player)
69
- io_interface.get_token(player)
70
- end
71
-
72
- it "returns the user input" do
73
- token = "X"
74
- allow(io).to receive(:solicit_input) { token }
75
-
76
- expect(io_interface.get_token(player)).to equal(token)
77
- end
78
- end
79
-
80
-
81
- describe '#get_difficulty' do
82
- let(:difficulty) { "HARD" }
83
-
84
- it "displays a difficulty solicitation" do
85
- allow(io).to receive(:solicit_input) { difficulty }
86
-
87
- expect(io_interface).to receive(:difficulty_solicitation)
88
- io_interface.get_difficulty
89
- end
90
-
91
- it "returns the user input (downcased and converted into a symbol)" do
92
- allow(io).to receive(:solicit_input) { difficulty }
93
-
94
- expect(io_interface.get_difficulty).to equal(:hard)
95
- end
96
- end
97
-
98
-
99
- describe '#draw_board' do
100
- it "displays a board string" do
101
- board = TicTacToes::Board.new
102
- board_string = strings.board(board)
103
-
104
- expect(io).to receive(:display).with(board_string)
105
- io_interface.draw_board(board)
106
- end
107
- end
108
-
109
-
110
- describe '#invalid_row_size_error' do
111
- it "displays a red invalid row size message" do
112
- expect(io).to receive(:display_red).with(strings::INVALID_ROW_SIZE)
113
- io_interface.invalid_row_size_error
114
- end
115
- end
116
-
117
-
118
- describe '#invalid_token_error' do
119
- it "displays a red invalid token message" do
120
- expect(io).to receive(:display_red).with(strings::INVALID_TOKEN)
121
- io_interface.invalid_token_error
122
- end
123
- end
124
-
125
-
126
- describe '#invalid_difficulty_error' do
127
- it "displays a red invalid difficulty message" do
128
- expect(io).to receive(:display_red).with(strings::INVALID_DIFFICULTY)
129
- io_interface.invalid_difficulty_error
130
- end
131
- end
132
-
133
-
134
- describe '#invalid_move_error' do
135
- it "displays a red invalid move message" do
136
- expect(io).to receive(:display_red).with(strings::INVALID_MOVE)
137
- io_interface.invalid_move_error
138
- end
139
- end
140
-
141
-
142
- describe '#thinking_notification' do
143
- it "displays a red thinking message" do
144
- expect(io).to receive(:display_red).with(strings::THINKING)
145
- io_interface.thinking_notification
146
- end
147
- end
148
-
149
-
150
- describe '#game_over_notification' do
151
- it "displays a game over message with the name of the winner" do
152
- winner = :X
153
- game_over_message = strings.game_over_notification(winner)
154
-
155
- expect(io).to receive(:display).with(game_over_message)
156
- io_interface.game_over_notification(winner)
157
- end
158
- end
159
-
160
-
161
- describe '#red' do
162
- it "calls its IO's red method with the passed message" do
163
- expect(io).to receive(:red).with("message")
164
- io_interface.red("message")
165
- end
166
- end
167
-
168
-
169
- describe '#blue' do
170
- it "calls its IO's blue method with the passed message" do
171
- expect(io).to receive(:blue).with("message")
172
- io_interface.blue("message")
173
- end
174
- end
175
- end
@@ -1,22 +0,0 @@
1
- require 'tic_tac_toes/medium_ai'
2
- require 'tic_tac_toes/spec_helper'
3
-
4
- describe TicTacToes::MediumAI do
5
- let(:ai) { TicTacToes::MediumAI }
6
- let(:x) { TicTacToes::Player.new("decider", "x", false, "interface") }
7
- let(:o) { TicTacToes::Player.new(ai, "o", true, "interface") }
8
- let(:players) { [x, o] }
9
-
10
- describe '#make_move' do
11
- it "makes a valid move (based on either EasyAI or HardAI)" do
12
- structure = [ o, o, x,
13
- nil, x, nil,
14
- nil, x, nil]
15
- board = generate_board(structure)
16
- valid_moves = [3, 5, 6, 8]
17
-
18
- move = ai.make_move(board, players)
19
- expect(valid_moves).to include(move)
20
- end
21
- end
22
- end
@@ -1,13 +0,0 @@
1
- require 'tic_tac_toes/board'
2
-
3
- def generate_board(structure)
4
- board_size = structure.count
5
- row_size = Math.sqrt(board_size)
6
- board = TicTacToes::Board.new(row_size: row_size)
7
-
8
- structure.each_with_index do |player, index|
9
- board.place(player, index)
10
- end
11
-
12
- board
13
- end