tactical_tic_tac_toe 0.2.0 → 1.0.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 91f9d2072259b9710988edde50d53c39cc3962e7
4
- data.tar.gz: fb68237c3ad7abf7c4259fef3bffc81d45701629
3
+ metadata.gz: a48e3069e89982be0b1927358042ccdf5931e344
4
+ data.tar.gz: 199d9b74f5bc4c0eab7e68ab78a6ee8534832688
5
5
  SHA512:
6
- metadata.gz: 0232937a96a30ad91f9d27fbb38cd67edfd6a7f5e327557edfb2859faa4dd60fe4fa396bc6732c10fee0fe1bcd2c8f9a823a1beacfe6bfa4758b9fd322cd8a10
7
- data.tar.gz: 2303ffecb1799bfda197289f85d7e418b34edb71efa5f5a83a87d16853d86f2c77df5dfcd34dd5ebdb7fd4e0cb08c252ebdd0305d464e34fb3f3a86b845847f8
6
+ metadata.gz: 87fa250b8b7f466e6fb30c39f4db48a08aa6e7bc79494180d63b5698a67ce89d1418f4bcda55b1c45dd6b8b543b92c33d8b7999c6aa5f4ba16b5e5da6af3470c
7
+ data.tar.gz: 1928f444469351637902c7a8afaecd00fed4fa18b5ad883ba913b730a1957446000b91bed94194f44ae96659fbf08402c2c897af6e34786081305a5c0ea737cd
data/lib/board.rb CHANGED
@@ -5,19 +5,25 @@ module TicTacToe
5
5
  attr_reader :size, :last_move_made
6
6
 
7
7
  def initialize(parameters)
8
- @size = parameters[:size]
9
- @cells = parameters[:config] || blank_board_configuration
8
+ @size = parameters[:size] || infer_size(parameters[:marked_spaces])
9
+ @spaces = parameters[:marked_spaces] || blank_spaces
10
10
  @last_move_made = parameters[:last_move_made]
11
11
  end
12
12
 
13
- def read_cell(row, col)
14
- @cells[row * @size + col]
13
+ def read_space(coordinates)
14
+ @spaces[coordinates_to_flat_index(coordinates)]
15
15
  end
16
16
 
17
- def mark_cell(mark, row, col)
18
- config = @cells.dup
19
- config[row * @size + col] = mark
20
- Board.new(size: @size, config: config, last_move_made: [row, col])
17
+ def mark_space(mark, coordinates)
18
+ marked_spaces = @spaces.dup
19
+ marked_spaces[coordinates_to_flat_index(coordinates)] = mark
20
+
21
+ Board.new(marked_spaces: marked_spaces, last_move_made: coordinates)
22
+ end
23
+
24
+ def last_mark_made
25
+ return if @last_move_made.nil?
26
+ self.read_space(last_move_made)
21
27
  end
22
28
 
23
29
  def lines
@@ -30,27 +36,22 @@ module TicTacToe
30
36
  (0...@size).to_a.repeated_permutation(2).to_a
31
37
  end
32
38
 
33
- def blank_cell_coordinates
39
+ def blank_space_coordinates
34
40
  all_coordinates.reject { |coordinates| marked?(coordinates) }
35
41
  end
36
42
 
37
- def last_mark_made
38
- return if @last_move_made.nil?
39
- self.read_cell(*last_move_made)
43
+ def out_of_bounds?(coordinates)
44
+ coordinates.any? { |i| !i.between?(0, @size - 1) }
40
45
  end
41
46
 
42
47
  def blank?(coordinates)
43
- self.read_cell(*coordinates) == BLANK_MARK
48
+ self.read_space(coordinates) == BLANK_MARK
44
49
  end
45
50
 
46
51
  def marked?(coordinates)
47
52
  !blank?(coordinates)
48
53
  end
49
54
 
50
- def out_of_bounds?(coordinates)
51
- coordinates.any? { |i| !i.between?(0, @size - 1) }
52
- end
53
-
54
55
  def all_blank?
55
56
  all_coordinates.all? { |coordinates| blank?(coordinates) }
56
57
  end
@@ -61,31 +62,41 @@ module TicTacToe
61
62
 
62
63
  def has_winning_line?
63
64
  lines.each do |line|
64
- return true if line.first != BLANK_MARK && line.all? { |cell| cell == line.first }
65
+ return true if line.first != BLANK_MARK && line.all? { |mark| mark == line.first }
65
66
  end
66
67
  false
67
68
  end
68
69
 
69
70
  private
70
71
 
71
- def blank_board_configuration
72
+ def infer_size(marked_spaces)
73
+ return if marked_spaces.nil?
74
+ Math.sqrt(marked_spaces.count).to_i
75
+ end
76
+
77
+ def coordinates_to_flat_index(coordinates)
78
+ row, col = coordinates
79
+ row * @size + col
80
+ end
81
+
82
+ def blank_spaces
72
83
  Array.new(@size**2) { BLANK_MARK }
73
84
  end
74
85
 
75
86
  def row_at(row)
76
- (0...@size).map { |col| self.read_cell(row, col) }
87
+ (0...@size).map { |col| self.read_space([row, col]) }
77
88
  end
78
89
 
79
90
  def col_at(col)
80
- (0...@size).map { |row| self.read_cell(row, col) }
91
+ (0...@size).map { |row| self.read_space([row, col]) }
81
92
  end
82
93
 
83
94
  def left_diag
84
- (0...@size).map { |index| self.read_cell(index, index) }
95
+ (0...@size).map { |index| self.read_space([index, index]) }
85
96
  end
86
97
 
87
98
  def right_diag
88
- (0...@size).map { |row| self.read_cell(row, @size - row - 1) }
99
+ (0...@size).map { |row| self.read_space([row, @size - row - 1]) }
89
100
  end
90
101
  end
91
102
  end
@@ -1,6 +1,5 @@
1
1
  module TicTacToe
2
2
  class CommandLineInterface
3
-
4
3
  def initialize(parameters)
5
4
  @input = parameters[:input]
6
5
  @output = parameters[:output]
@@ -86,7 +85,7 @@ EOS
86
85
  (0...board.size).each do |row|
87
86
  output_string += col_separator
88
87
  (0...board.size).each do |col|
89
- output_string += " #{board.read_cell(row, col) || " "} " + col_separator
88
+ output_string += " #{board.read_space([row, col]) || " "} " + col_separator
90
89
  end
91
90
  output_string += "\n" + row_separator
92
91
  end
@@ -47,9 +47,9 @@ module TicTacToe
47
47
  board = node.fetch(:board)
48
48
  current_player_mark = node.fetch(:current_player_mark)
49
49
 
50
- board.blank_cell_coordinates.map do |coordinates|
50
+ board.blank_space_coordinates.map do |coordinates|
51
51
  child_node = {
52
- board: board.mark_cell(current_player_mark, *coordinates),
52
+ board: board.mark_space(current_player_mark, coordinates),
53
53
  current_player_mark: toggle_mark(current_player_mark),
54
54
  last_move_made: coordinates
55
55
  }
@@ -71,8 +71,8 @@ module TicTacToe
71
71
  board = node.fetch(:board)
72
72
 
73
73
  board.lines.each do |line|
74
- return 1 if line.all? { |cell| cell == @player_mark }
75
- return -1 if line.all? { |cell| cell == @opponent_mark }
74
+ return 1 if line.all? { |mark| mark == @player_mark }
75
+ return -1 if line.all? { |mark| mark == @opponent_mark }
76
76
  end
77
77
  0
78
78
  end
data/lib/game.rb CHANGED
@@ -37,7 +37,7 @@ module TicTacToe
37
37
  def handle_one_turn(current_player)
38
38
  @interface.show_game_board(@board)
39
39
  coordinates = get_valid_move(current_player)
40
- @board = @board.mark_cell(current_player.player_mark, *coordinates)
40
+ @board = @board.mark_space(current_player.player_mark, coordinates)
41
41
  @interface.report_move(current_player.player_mark, coordinates)
42
42
  end
43
43
 
@@ -77,12 +77,12 @@ module TicTacToe
77
77
  end
78
78
 
79
79
  def create_player(mark, type)
80
- player_config = {
80
+ player_parameters = {
81
81
  type: type,
82
82
  game: self,
83
83
  player_mark: mark
84
84
  }
85
- PlayerFactory.build(player_config)
85
+ PlayerFactory.build(player_parameters)
86
86
  end
87
87
  end
88
88
  end
@@ -4,30 +4,30 @@ require "available_player_types"
4
4
 
5
5
  module TicTacToe
6
6
  module PlayerFactory
7
- def self.build(config)
8
- case config[:type]
7
+ def self.build(parameters)
8
+ case parameters[:type]
9
9
  when AvailablePlayerTypes::HUMAN
10
- create_human_player(config)
10
+ create_human_player(parameters)
11
11
  when AvailablePlayerTypes::COMPUTER
12
- create_computer_player(config)
12
+ create_computer_player(parameters)
13
13
  end
14
14
  end
15
15
 
16
16
  private
17
17
 
18
- def self.create_human_player(config)
18
+ def self.create_human_player(parameters)
19
19
  human_parameters = {
20
- player_mark: config[:player_mark],
21
- interface: config[:game].interface
20
+ player_mark: parameters[:player_mark],
21
+ interface: parameters[:game].interface
22
22
  }
23
23
  HumanPlayer.new(human_parameters)
24
24
  end
25
25
 
26
- def self.create_computer_player(config)
26
+ def self.create_computer_player(parameters)
27
27
  computer_parameters = {
28
- player_mark: config[:player_mark],
29
- opponent_mark: (config[:game].player_marks - [config[:player_mark]]).pop,
30
- board: config[:game].board
28
+ player_mark: parameters[:player_mark],
29
+ opponent_mark: (parameters[:game].player_marks - [parameters[:player_mark]]).pop,
30
+ board: parameters[:game].board
31
31
  }
32
32
  ComputerPlayer.new(computer_parameters)
33
33
  end
data/spec/board_spec.rb CHANGED
@@ -11,26 +11,26 @@ module TicTacToe
11
11
  let(:o) { @default_player_marks.last }
12
12
 
13
13
  describe "#initialize" do
14
- context "given the configuration of a board with preexisting marks" do
15
- let(:config) do
14
+ context "given a set of preexisting marks" do
15
+ let(:marked_spaces) do
16
16
  [ x, _, _,
17
17
  _, o, _,
18
18
  _, _, x ]
19
19
  end
20
20
 
21
- it "generates a board with the specified marks in each cell" do
22
- board = new_board(size: Math.sqrt(config.size).to_i, config: config)
21
+ it "generates a board with the specified marks in each space" do
22
+ board = build_board(marked_spaces)
23
23
 
24
- board.all_coordinates.zip(config).each do |coordinates, mark|
25
- expect(board.read_cell(*coordinates)).to eq mark
24
+ board.all_coordinates.zip(marked_spaces).each do |coordinates, mark|
25
+ expect(board.read_space(coordinates)).to eq mark
26
26
  end
27
27
  end
28
28
  end
29
29
 
30
- context "when not given a configuration of a board with preexisting marks" do
30
+ context "when not given a a set of preexisting marks" do
31
31
  it "generates a NxN board of the given size" do
32
32
  (3..5).each do |size|
33
- custom_board = new_board(size: size)
33
+ custom_board = blank_board(size)
34
34
 
35
35
  expect(custom_board.size).to eq size
36
36
  expect(custom_board.all_coordinates.count).to eq size**2
@@ -38,23 +38,21 @@ module TicTacToe
38
38
  end
39
39
 
40
40
  it "leaves the generated board blank" do
41
- expect(new_board(size: @default_board_size).all_blank?).to be true
41
+ expect(blank_board(@default_board_size).all_blank?).to be true
42
42
  end
43
43
  end
44
44
  end
45
45
 
46
- describe "#read_cell" do
47
- it "gets the contents of cell at given row and column" do
48
- mark = @default_player_marks.sample
49
- config = blank_board_configuration(@default_board_size)
50
- config[0] = mark
51
- board = build_board(config)
46
+ describe "#read_space" do
47
+ it "gets the contents of space at given row and column" do
48
+ marked_spaces = [x, _, _, _, _, _, _, _, _]
49
+ board = build_board(marked_spaces)
52
50
 
53
- expect(board.read_cell(0, 0)).to eq mark
51
+ expect(board.read_space([0, 0])).to eq x
54
52
  end
55
53
  end
56
54
 
57
- describe "#mark_cell" do
55
+ describe "#mark_space" do
58
56
  let(:board) { blank_board(@default_board_size) }
59
57
  let(:coordinates) { random_coordinates(board.size) }
60
58
  let(:mark) { @default_player_marks.sample }
@@ -62,19 +60,19 @@ module TicTacToe
62
60
  it "returns a new board with the given coordinates played" do
63
61
  board = blank_board(@default_board_size)
64
62
 
65
- expect(board.mark_cell(mark, *coordinates).read_cell(*coordinates)).to eq(mark)
63
+ expect(board.mark_space(mark, coordinates).read_space(coordinates)).to eq(mark)
66
64
  end
67
65
 
68
66
  it "does not mutate the board" do
69
67
  board = blank_board(@default_board_size)
70
68
 
71
- board.mark_cell(mark, *coordinates)
69
+ board.mark_space(mark, coordinates)
72
70
 
73
71
  expect(board).to be_all_blank
74
72
  end
75
73
 
76
74
  it "records the coordinates of the last mark made" do
77
- returned_board = board.mark_cell(mark, *coordinates)
75
+ returned_board = board.mark_space(mark, coordinates)
78
76
 
79
77
  expect(returned_board.last_move_made).to eq coordinates
80
78
  end
@@ -96,33 +94,33 @@ module TicTacToe
96
94
  describe "#all_coordinates" do
97
95
  let(:board) { blank_board(@default_board_size) }
98
96
 
99
- it "returns the coordinates of every cell in board" do
97
+ it "returns the coordinates of every space in board" do
100
98
  all_coordinates = (0...board.size).to_a.repeated_permutation(2).to_a
101
99
 
102
100
  expect(board.all_coordinates).to match_array all_coordinates
103
101
  end
104
102
  end
105
103
 
106
- describe "#blank_cell_coordinates" do
107
- it "returns all cell coordinates when board is blank" do
104
+ describe "#blank_space_coordinates" do
105
+ it "returns all space coordinates when board is blank" do
108
106
  board = blank_board(@default_board_size)
109
107
 
110
- expect(board.blank_cell_coordinates).to match_array board.all_coordinates
108
+ expect(board.blank_space_coordinates).to match_array board.all_coordinates
111
109
  end
112
110
 
113
- it "returns the coordinates of all blank cells in board" do
114
- config = [x, o, _, _, _, _, _, _, _].shuffle
115
- board = build_board(config)
111
+ it "returns the coordinates of all blank spaces in board" do
112
+ marked_spaces = [x, o, _, _, _, _, _, _, _].shuffle
113
+ board = build_board(marked_spaces)
116
114
  unmarked_coordinates = board.all_coordinates.reject { |coords| board.marked?(coords) }
117
115
 
118
- expect(board.blank_cell_coordinates).to match_array unmarked_coordinates
116
+ expect(board.blank_space_coordinates).to match_array unmarked_coordinates
119
117
  end
120
118
 
121
- it "returns no coordinates when no cells are blank" do
122
- config = [x, o, x, o, x, o, x, o, x].shuffle
123
- board = build_board(config)
119
+ it "returns no coordinates when no spaces are blank" do
120
+ marked_spaces = [x, o, x, o, x, o, x, o, x].shuffle
121
+ board = build_board(marked_spaces)
124
122
 
125
- expect(board.blank_cell_coordinates.count).to eq 0
123
+ expect(board.blank_space_coordinates.count).to eq 0
126
124
  end
127
125
  end
128
126
 
@@ -137,7 +135,7 @@ module TicTacToe
137
135
  it "returns the last mark made on the board" do
138
136
  board = blank_board(@default_board_size)
139
137
  mark = @default_player_marks.sample
140
- returned_board = board.mark_cell(mark, *random_coordinates(board.size))
138
+ returned_board = board.mark_space(mark, random_coordinates(board.size))
141
139
 
142
140
  expect(returned_board.last_mark_made).to eq mark
143
141
  end
@@ -145,31 +143,31 @@ module TicTacToe
145
143
  end
146
144
 
147
145
  describe "#blank?" do
148
- it "returns true if cell at given coordinates is blank" do
146
+ it "returns true if space at given coordinates is blank" do
149
147
  board = blank_board(@default_board_size)
150
148
 
151
149
  expect(board.blank?(random_coordinates(board.size))).to be true
152
150
  end
153
151
 
154
- it "returns false if cell at given coordinates is not blank" do
152
+ it "returns false if space at given coordinates is not blank" do
155
153
  board = blank_board(@default_board_size)
156
154
  coordinates = random_coordinates(board.size)
157
- returned_board = board.mark_cell(@default_player_marks.sample, *coordinates)
155
+ returned_board = board.mark_space(@default_player_marks.sample, coordinates)
158
156
 
159
157
  expect(returned_board.blank?(coordinates)).to be false
160
158
  end
161
159
  end
162
160
 
163
161
  describe "#marked?" do
164
- it "returns true if cell at given coordinates has any player's mark" do
162
+ it "returns true if space at given coordinates has any player's mark" do
165
163
  board = blank_board(@default_board_size)
166
164
  coordinates = random_coordinates(board.size)
167
- returned_board = board.mark_cell(@default_player_marks.sample, *coordinates)
165
+ returned_board = board.mark_space(@default_player_marks.sample, coordinates)
168
166
 
169
167
  expect(returned_board.marked?(coordinates)).to be true
170
168
  end
171
169
 
172
- it "returns false if cell at given coordinates does not have a player's mark" do
170
+ it "returns false if space at given coordinates does not have a player's mark" do
173
171
  blank_board = blank_board(@default_board_size)
174
172
  coordinates = random_coordinates(blank_board.size)
175
173
 
@@ -195,31 +193,31 @@ module TicTacToe
195
193
  end
196
194
 
197
195
  describe "#all_blank?" do
198
- it "returns true if no cell in board is marked" do
196
+ it "returns true if no space in board is marked" do
199
197
  board = blank_board(@default_board_size)
200
198
 
201
199
  expect(board.all_blank?).to be true
202
200
  end
203
201
 
204
- it "returns false if any cell in board is marked" do
205
- config = [x, _, _, _, _, _, _, _, _].shuffle
206
- board = build_board(config)
202
+ it "returns false if any space in board is marked" do
203
+ marked_spaces = [x, _, _, _, _, _, _, _, _].shuffle
204
+ board = build_board(marked_spaces)
207
205
 
208
206
  expect(board.all_blank?).to be false
209
207
  end
210
208
  end
211
209
 
212
210
  describe "#all_marked?" do
213
- it "returns true if all cells in board are marked" do
214
- config = [x, x, x, x, x, o, o, o, o].shuffle
215
- board = build_board(config)
211
+ it "returns true if all spaces in board are marked" do
212
+ marked_spaces = [x, x, x, x, x, o, o, o, o].shuffle
213
+ board = build_board(marked_spaces)
216
214
 
217
215
  expect(board.all_marked?).to be true
218
216
  end
219
217
 
220
- it "returns false if any cell in board is blank" do
221
- config = [x, x, x, x, _, o, o, o, o].shuffle
222
- board = build_board(config)
218
+ it "returns false if any space in board is blank" do
219
+ marked_spaces = [x, x, x, x, _, o, o, o, o].shuffle
220
+ board = build_board(marked_spaces)
223
221
 
224
222
  expect(board.all_marked?).to be false
225
223
  end
@@ -227,7 +225,7 @@ module TicTacToe
227
225
 
228
226
  describe "#has_winning_line?" do
229
227
  it "returns true if board has a horizontal winning line" do
230
- winning_configs = [
228
+ winning_configurations = [
231
229
  [ x, x, x,
232
230
  _, _, _,
233
231
  _, _, _ ],
@@ -239,13 +237,13 @@ module TicTacToe
239
237
  x, x, x ]
240
238
  ]
241
239
 
242
- winning_configs.each do |config|
243
- expect(build_board(config).has_winning_line?).to be true
240
+ winning_configurations.each do |marked_spaces|
241
+ expect(build_board(marked_spaces).has_winning_line?).to be true
244
242
  end
245
243
  end
246
244
 
247
245
  it "returns true if board has a vertical winning line" do
248
- winning_configs = [
246
+ winning_configurations = [
249
247
  [ x, _, _,
250
248
  x, _, _,
251
249
  x, _, _ ],
@@ -257,13 +255,13 @@ module TicTacToe
257
255
  _, _, x ]
258
256
  ]
259
257
 
260
- winning_configs.each do |config|
261
- expect(build_board(config).has_winning_line?).to be true
258
+ winning_configurations.each do |marked_spaces|
259
+ expect(build_board(marked_spaces).has_winning_line?).to be true
262
260
  end
263
261
  end
264
262
 
265
263
  it "returns true if board has a diagonal winning line" do
266
- winning_configs = [
264
+ winning_configurations = [
267
265
  [ x, _, _,
268
266
  _, x, _,
269
267
  _, _, x ],
@@ -272,13 +270,13 @@ module TicTacToe
272
270
  x, _, _ ]
273
271
  ]
274
272
 
275
- winning_configs.each do |config|
276
- expect(build_board(config).has_winning_line?).to be true
273
+ winning_configurations.each do |marked_spaces|
274
+ expect(build_board(marked_spaces).has_winning_line?).to be true
277
275
  end
278
276
  end
279
277
 
280
278
  it "returns false if board has no winning line" do
281
- non_winning_configs = [
279
+ non_winning_configurations = [
282
280
  [ _, _, _,
283
281
  _, _, _,
284
282
  _, _, _ ],
@@ -296,8 +294,8 @@ module TicTacToe
296
294
  o, x, o ]
297
295
  ]
298
296
 
299
- non_winning_configs.each do |config|
300
- expect(build_board(config).has_winning_line?).to be false
297
+ non_winning_configurations.each do |marked_spaces|
298
+ expect(build_board(marked_spaces).has_winning_line?).to be false
301
299
  end
302
300
  end
303
301
  end
@@ -15,6 +15,11 @@ module TicTacToe
15
15
  CommandLineInterface.new(parameters)
16
16
  end
17
17
 
18
+ def at_least_one_repeated_line?(string)
19
+ lines = string.split("\n")
20
+ lines.uniq.length < lines.length
21
+ end
22
+
18
23
  describe "#game_setup_interaction" do
19
24
  before do
20
25
  input_stream.string = %w(human computer).join("\n")
@@ -41,7 +46,7 @@ module TicTacToe
41
46
 
42
47
  it "prints a prompt to the command line" do
43
48
  input_stream.string = valid_input
44
- interface.solicit_player_type(@default_first_player)
49
+ interface.solicit_player_type(@default_player_marks.first)
45
50
 
46
51
  expect(output_stream.string).not_to eq ""
47
52
  end
@@ -50,7 +55,7 @@ module TicTacToe
50
55
  it "returns the player type input by user" do
51
56
  input_stream.string = valid_input
52
57
 
53
- expect(interface.solicit_player_type(@default_first_player)).to eq valid_input.to_sym
58
+ expect(interface.solicit_player_type(@default_player_marks.first)).to eq valid_input.to_sym
54
59
  end
55
60
  end
56
61
 
@@ -59,7 +64,7 @@ module TicTacToe
59
64
 
60
65
  it "prompts the user until given valid input" do
61
66
  input_stream.string = invalid_input + "\n" + invalid_input + "\n" + valid_input
62
- interface.solicit_player_type(@default_first_player)
67
+ interface.solicit_player_type(@default_player_marks.first)
63
68
 
64
69
  expect(at_least_one_repeated_line?(output_stream.string)).to be true
65
70
  end
@@ -67,17 +72,17 @@ module TicTacToe
67
72
  end
68
73
 
69
74
  describe "#show_game_board" do
75
+ let(:_) { Board::BLANK_MARK }
76
+ let(:x) { @default_player_marks.first }
77
+ let(:o) { @default_player_marks.last }
78
+
70
79
  it "prints a respresentation of the given board to the command line" do
71
- board = board_with_draw(@default_board_size, @default_player_marks)
80
+ board = build_board([x, x, x, o, o, o, _, _, _])
72
81
  interface.show_game_board(board)
73
-
74
82
  board_characters = output_stream.string.split("")
75
- cell_count = board.size**2
76
- expected_first_mark_count = cell_count.odd? ? cell_count / 2 + 1 : cell_count / 2
77
- expected_second_mark_count = cell_count / 2
78
83
 
79
- expect(board_characters.count(@default_first_player.to_s)).to eq expected_first_mark_count
80
- expect(board_characters.count(@default_second_player.to_s)).to eq expected_second_mark_count
84
+ expect(board_characters.count(x.to_s)).to eq 3
85
+ expect(board_characters.count(o.to_s)).to eq 3
81
86
  end
82
87
  end
83
88
 
@@ -86,7 +91,7 @@ module TicTacToe
86
91
 
87
92
  it "prints a prompt to the command line" do
88
93
  input_stream.string = valid_input
89
- interface.solicit_move(@default_first_player)
94
+ interface.solicit_move(@default_player_marks.first)
90
95
 
91
96
  expect(output_stream.string).not_to eq ""
92
97
  end
@@ -96,7 +101,7 @@ module TicTacToe
96
101
  input_stream.string = valid_input
97
102
  valid_coordinate = valid_input.split(",").map(&:to_i)
98
103
 
99
- expect(interface.solicit_move(@default_first_player)).to eq valid_coordinate
104
+ expect(interface.solicit_move(@default_player_marks.first)).to eq valid_coordinate
100
105
  end
101
106
  end
102
107
 
@@ -105,7 +110,7 @@ module TicTacToe
105
110
 
106
111
  it "prompts the user until given valid input" do
107
112
  input_stream.string = invalid_input + "\n" + invalid_input + "\n" + valid_input
108
- interface.solicit_move(@default_first_player)
113
+ interface.solicit_move(@default_player_marks.first)
109
114
 
110
115
  expect(at_least_one_repeated_line?(output_stream.string)).to be true
111
116
  end
@@ -122,10 +127,10 @@ module TicTacToe
122
127
 
123
128
  describe "#report_move" do
124
129
  it "prints a notification of the move made by the given mark at the given coordinates" do
125
- interface.report_move(@default_first_player, [0, 0])
130
+ interface.report_move(@default_player_marks.first, [0, 0])
126
131
  interface_output = output_stream.string
127
132
 
128
- expect(interface_output).to include @default_first_player.to_s
133
+ expect(interface_output).to include @default_player_marks.first.to_s
129
134
  expect(interface_output.split("").count("0")).to eq 2
130
135
  end
131
136
  end
@@ -133,8 +138,8 @@ module TicTacToe
133
138
  describe "#report_game_over" do
134
139
  context "when given the mark of a winning player" do
135
140
  it "prints a notification that the player has won" do
136
- expect(interface).to receive(:report_win).with(@default_first_player)
137
- interface.report_game_over(@default_first_player)
141
+ expect(interface).to receive(:report_win).with(@default_player_marks.first)
142
+ interface.report_game_over(@default_player_marks.first)
138
143
  end
139
144
  end
140
145
 
@@ -148,10 +153,10 @@ module TicTacToe
148
153
 
149
154
  describe "#report_win" do
150
155
  it "prints a notification that the player using the given mark has won" do
151
- interface.report_win(@default_first_player)
156
+ interface.report_win(@default_player_marks.first)
152
157
  interface_output = output_stream.string
153
158
 
154
- expect(interface_output).to include @default_first_player.to_s
159
+ expect(interface_output).to include @default_player_marks.first.to_s
155
160
  expect(interface_output).to include "wins"
156
161
  end
157
162
  end
@@ -10,8 +10,8 @@ module TicTacToe
10
10
  include_context "helper_methods"
11
11
 
12
12
  let(:_) { Board::BLANK_MARK }
13
- let(:x) { @default_first_player }
14
- let(:o) { @default_second_player }
13
+ let(:x) { @default_player_marks.first }
14
+ let(:o) { @default_player_marks.last }
15
15
 
16
16
  def new_computer_player(parameters)
17
17
  ComputerPlayer.new(parameters)
@@ -37,12 +37,12 @@ module TicTacToe
37
37
 
38
38
  describe "#move" do
39
39
  it "returns the coordinates of a valid move" do
40
- board_config = [
40
+ marked_spaces = [
41
41
  x, o, x,
42
42
  x, x, o,
43
43
  o, _, _
44
44
  ]
45
- board = build_board(board_config).mark_cell(o, *[2, 1])
45
+ board = build_board(marked_spaces).mark_space(o, [2, 1])
46
46
  game = Game.new(board: board)
47
47
  computer_player = x_player(board)
48
48
  coordinates = computer_player.move(game)
@@ -64,7 +64,7 @@ module TicTacToe
64
64
 
65
65
  context "when computer player can make a horizontal winning move" do
66
66
  it "returns the coordinates of the winning move" do
67
- board_configs = [
67
+ board_configurations = [
68
68
  [ x, _, x,
69
69
  _, o, _,
70
70
  o, x, o ],
@@ -76,8 +76,8 @@ module TicTacToe
76
76
  _, x, x ]
77
77
  ]
78
78
  winning_moves = [[0, 1], [1, 2], [2, 0]]
79
- board_configs.zip(winning_moves).each do |board_config, winning_move|
80
- board = build_board(board_config)
79
+ board_configurations.zip(winning_moves).each do |marked_spaces, winning_move|
80
+ board = build_board(marked_spaces)
81
81
  game = Game.new(board: board)
82
82
  computer_player = x_player(board)
83
83
 
@@ -88,7 +88,7 @@ module TicTacToe
88
88
 
89
89
  context "when computer player can make a vertical winning move" do
90
90
  it "returns the coordinates of the winning move" do
91
- board_configs = [
91
+ board_configurations = [
92
92
  [ x, _, o,
93
93
  _, o, x,
94
94
  x, _, o ],
@@ -100,8 +100,8 @@ module TicTacToe
100
100
  o, x, x ]
101
101
  ]
102
102
  winning_moves = [[1, 0], [2, 1], [0, 2]]
103
- board_configs.zip(winning_moves).each do |board_config, winning_move|
104
- board = build_board(board_config)
103
+ board_configurations.zip(winning_moves).each do |marked_spaces, winning_move|
104
+ board = build_board(marked_spaces)
105
105
  game = Game.new(board: board)
106
106
  computer_player = x_player(board)
107
107
 
@@ -112,7 +112,7 @@ module TicTacToe
112
112
 
113
113
  context "when computer player can make a diagonal winning move" do
114
114
  it "returns the coordinates of the winning move" do
115
- board_configs = [
115
+ board_configurations = [
116
116
  [ x, _, o,
117
117
  o, x, _,
118
118
  x, o, _ ],
@@ -121,8 +121,8 @@ module TicTacToe
121
121
  x, o, _ ]
122
122
  ]
123
123
  winning_moves = [[2, 2], [0, 2]]
124
- board_configs.zip(winning_moves).each do |board_config, winning_move|
125
- board = build_board(board_config)
124
+ board_configurations.zip(winning_moves).each do |marked_spaces, winning_move|
125
+ board = build_board(marked_spaces)
126
126
  computer_player = x_player(board)
127
127
  game = Game.new(board: board)
128
128
 
@@ -133,7 +133,7 @@ module TicTacToe
133
133
 
134
134
  context "when opponent can make a horizontal winning move next turn" do
135
135
  it "returns the coordinates of the move that blocks the opponent from winning" do
136
- board_configs = [
136
+ board_configurations = [
137
137
  [ x, _, x,
138
138
  _, o, _,
139
139
  o, x, o ],
@@ -145,8 +145,8 @@ module TicTacToe
145
145
  _, x, x ]
146
146
  ]
147
147
  winning_moves = [[0, 1], [1, 2], [2, 0]]
148
- board_configs.zip(winning_moves).each do |board_config, winning_move|
149
- board = build_board(board_config)
148
+ board_configurations.zip(winning_moves).each do |marked_spaces, winning_move|
149
+ board = build_board(marked_spaces)
150
150
  computer_player = o_player(board)
151
151
  game = Game.new(board: board)
152
152
 
@@ -157,7 +157,7 @@ module TicTacToe
157
157
 
158
158
  context "when opponent can make a vertical winning move next turn" do
159
159
  it "returns the coordinates of the move that blocks the opponent from winning" do
160
- board_configs = [
160
+ board_configurations = [
161
161
  [ x, _, o,
162
162
  _, o, x,
163
163
  x, _, o ],
@@ -169,8 +169,8 @@ module TicTacToe
169
169
  o, x, x ]
170
170
  ]
171
171
  winning_moves = [[1, 0], [2, 1], [0, 2]]
172
- board_configs.zip(winning_moves).each do |board_config, winning_move|
173
- board = build_board(board_config)
172
+ board_configurations.zip(winning_moves).each do |marked_spaces, winning_move|
173
+ board = build_board(marked_spaces)
174
174
  computer_player = o_player(board)
175
175
  game = Game.new(board: board)
176
176
 
@@ -181,7 +181,7 @@ module TicTacToe
181
181
 
182
182
  context "when opponent can make a diagonal winning move next turn" do
183
183
  it "returns the coordinates of the move that blocks the opponent from winning" do
184
- board_configs = [
184
+ board_configurations = [
185
185
  [ x, _, o,
186
186
  o, x, _,
187
187
  x, o, _ ],
@@ -190,8 +190,8 @@ module TicTacToe
190
190
  x, o, _ ]
191
191
  ]
192
192
  winning_moves = [[2, 2], [0, 2]]
193
- board_configs.zip(winning_moves).each do |board_config, winning_move|
194
- board = build_board(board_config)
193
+ board_configurations.zip(winning_moves).each do |marked_spaces, winning_move|
194
+ board = build_board(marked_spaces)
195
195
  computer_player = o_player(board)
196
196
  game = Game.new(board: board)
197
197
 
@@ -202,7 +202,7 @@ module TicTacToe
202
202
 
203
203
  context "when opponent can make a fork next turn" do
204
204
  it "returns the coordinates of a move that prevents that fork" do
205
- board_configs = [
205
+ board_configurations = [
206
206
  [ x, _, _,
207
207
  _, x, _,
208
208
  _, _, o ],
@@ -218,8 +218,8 @@ module TicTacToe
218
218
  [[0, 1], [1, 0], [1, 2], [2, 1]],
219
219
  [[0, 0], [0, 2], [2, 0], [2, 2]]
220
220
  ]
221
- board_configs.zip(good_move_sets).each do |board_config, good_moves|
222
- board = build_board(board_config)
221
+ board_configurations.zip(good_move_sets).each do |marked_spaces, good_moves|
222
+ board = build_board(marked_spaces)
223
223
  computer_player = o_player(board)
224
224
  game = Game.new(board: board)
225
225
 
data/spec/game_spec.rb CHANGED
@@ -114,7 +114,7 @@ module TicTacToe
114
114
  let(:player_stub) { Object.new }
115
115
 
116
116
  before do
117
- allow(player_stub).to receive(:player_mark).and_return(@default_first_player)
117
+ allow(player_stub).to receive(:player_mark).and_return(@default_player_marks.first)
118
118
  allow(player_stub).to receive(:move).and_return([0, 0])
119
119
  end
120
120
 
@@ -138,13 +138,13 @@ module TicTacToe
138
138
  allow(game.interface).to receive(:report_move)
139
139
  game.handle_one_turn(player_stub)
140
140
 
141
- expect(game.board.read_cell(0, 0)).to eq @default_first_player
141
+ expect(game.board.read_space([0, 0])).to eq @default_player_marks.first
142
142
  end
143
143
 
144
144
  it "reports the move that was just made through the interface" do
145
145
  allow(game.interface).to receive(:show_game_board)
146
146
 
147
- expect(game.interface).to receive(:report_move).with(@default_first_player, [0, 0])
147
+ expect(game.interface).to receive(:report_move).with(@default_player_marks.first, [0, 0])
148
148
  game.handle_one_turn(player_stub)
149
149
  end
150
150
  end
@@ -206,9 +206,9 @@ module TicTacToe
206
206
  it "reports that the given last player to move has won via the interface" do
207
207
  allow(game.interface).to receive(:show_game_board)
208
208
  allow(game.board).to receive(:has_winning_line?).and_return(true)
209
- allow(game.board).to receive(:last_mark_made).and_return(@default_first_player)
209
+ allow(game.board).to receive(:last_mark_made).and_return(@default_player_marks.first)
210
210
 
211
- expect(game.interface).to receive(:report_game_over).with(@default_first_player)
211
+ expect(game.interface).to receive(:report_game_over).with(@default_player_marks.first)
212
212
  game.handle_game_over
213
213
  end
214
214
  end
@@ -216,7 +216,7 @@ module TicTacToe
216
216
  context "when game has no winner" do
217
217
  it "reports that game ended in a draw via the interface" do
218
218
  allow(game.interface).to receive(:show_game_board)
219
- allow(game.board).to receive(:last_mark_made).and_return(@default_first_player)
219
+ allow(game.board).to receive(:last_mark_made).and_return(@default_player_marks.first)
220
220
 
221
221
  expect(game.interface).to receive(:report_game_over).with(:none)
222
222
  game.handle_game_over
@@ -277,7 +277,7 @@ module TicTacToe
277
277
 
278
278
  it "should end in a win for the computer player against an unskilled human player" do
279
279
  allow(game.interface).to receive(:solicit_move) do
280
- game.board.blank_cell_coordinates.first
280
+ game.board.blank_space_coordinates.first
281
281
  end
282
282
  computer_player_mark = :o
283
283
  game.run
@@ -8,8 +8,7 @@ module TicTacToe
8
8
  let(:interface) { double("CommandLineInterface") }
9
9
  let(:human_player) do
10
10
  HumanPlayer.new(
11
- # interface: interface,
12
- player_mark: @default_first_player)
11
+ player_mark: @default_player_marks.first)
13
12
  end
14
13
 
15
14
  describe "#move" do
@@ -10,38 +10,38 @@ module TicTacToe
10
10
  describe ".build" do
11
11
  let(:player_types) { [AvailablePlayerTypes::HUMAN, AvailablePlayerTypes::COMPUTER] }
12
12
  let(:player_classes) { [HumanPlayer, ComputerPlayer] }
13
- let(:player_config) do
13
+ let(:player_parameters) do
14
14
  {
15
15
  game: Game.new({}),
16
16
  player_mark: @default_player_marks.first
17
17
  }
18
18
  end
19
19
 
20
- def build_player(config)
21
- PlayerFactory.build(config)
20
+ def build_player(player_parameters)
21
+ PlayerFactory.build(player_parameters)
22
22
  end
23
23
 
24
24
  it "creates a player of the given type" do
25
25
  player_types.zip(player_classes).each do |type, player_class|
26
- player_config[:type] = type
26
+ player_parameters[:type] = type
27
27
 
28
- expect(build_player(player_config)).to be_a player_class
28
+ expect(build_player(player_parameters)).to be_a player_class
29
29
  end
30
30
  end
31
31
 
32
32
  it "creates players that respond to #move" do
33
33
  player_types.each do |type|
34
- player_config[:type] = type
34
+ player_parameters[:type] = type
35
35
 
36
- expect(build_player(player_config)).to respond_to :move
36
+ expect(build_player(player_parameters)).to respond_to :move
37
37
  end
38
38
  end
39
39
 
40
40
  it "creates players that use the given mark" do
41
41
  player_types.each do |type|
42
- player_config[:type] = type
42
+ player_parameters[:type] = type
43
43
 
44
- expect(build_player(player_config).player_mark).to eq player_config[:player_mark]
44
+ expect(build_player(player_parameters).player_mark).to eq player_parameters[:player_mark]
45
45
  end
46
46
  end
47
47
  end
data/spec/spec_helper.rb CHANGED
@@ -4,8 +4,6 @@ require "rspec/collection_matchers"
4
4
  RSpec.shared_context "default_values" do
5
5
  before :all do
6
6
  @default_board_size = 3
7
- @default_first_player = :x
8
- @default_second_player = :o
9
7
  @default_player_marks = [:x, :o]
10
8
  @default_player_types = [
11
9
  TicTacToe::AvailablePlayerTypes::HUMAN,
@@ -15,42 +13,15 @@ RSpec.shared_context "default_values" do
15
13
  end
16
14
 
17
15
  RSpec.shared_context "helper_methods" do
18
- def blank_board_configuration(board_size)
19
- (0...board_size**2).map { TicTacToe::Board::BLANK_MARK }
20
- end
21
-
22
- def at_least_one_repeated_line?(string)
23
- lines = string.split("\n")
24
- lines.uniq.length < lines.length
25
- end
26
-
27
16
  def random_coordinates(board_size)
28
17
  [rand(board_size), rand(board_size)]
29
18
  end
30
19
 
31
- def new_board(parameters)
32
- TicTacToe::Board.new(parameters)
33
- end
34
-
35
- def build_board(config)
36
- size = Math.sqrt(config.size).to_i
37
- new_board(size: size, config: config)
20
+ def build_board(marked_spaces)
21
+ TicTacToe::Board.new(marked_spaces: marked_spaces)
38
22
  end
39
23
 
40
24
  def blank_board(board_size)
41
- new_board(size: board_size)
42
- end
43
-
44
- def board_with_draw(board_size, player_marks)
45
- first_mark, second_mark = player_marks
46
- blank_board(board_size).blank_cell_coordinates.reduce(blank_board(board_size)) do |board, (row, col)|
47
- if row == 0
48
- mark = col.odd? ? first_mark : second_mark
49
- board.mark_cell(mark, row, col)
50
- else
51
- mark = col.even? ? first_mark : second_mark
52
- board.mark_cell(mark, row, col)
53
- end
54
- end
25
+ TicTacToe::Board.new(size: board_size)
55
26
  end
56
27
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tactical_tic_tac_toe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Batman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-26 00:00:00.000000000 Z
11
+ date: 2015-11-01 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Command line tic tac toe! Run with command 'ttt'
14
14
  email: no@no.no