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
@@ -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