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,73 +1,69 @@
1
- require 'tic_tac_toes/io_interface'
2
1
  require 'command_line/menu'
3
- require 'tic_tac_toes/medium_ai'
4
- require 'tic_tac_toes/spec_helper'
2
+ require 'tic_tac_toes/board_factory'
3
+ require 'tic_tac_toes/player_factory'
4
+ require 'tic_tac_toes/io'
5
+ require 'tic_tac_toes/move_strategies/human'
6
+ require 'tic_tac_toes/move_strategies/medium_ai'
5
7
 
6
8
  describe CommandLine::Menu do
7
- let(:io) { double("io") }
8
- let(:io_interface) { TicTacToes::IOInterface.new(io) }
9
- let(:menu) { CommandLine::Menu.new(io_interface) }
10
-
9
+ let(:io) { double }
10
+ let(:board_factory) { TicTacToes::BoardFactory.new }
11
+ let(:player_factory) { TicTacToes::PlayerFactory.new(io) }
12
+ let(:menu) { CommandLine::Menu.new(io, board_factory, player_factory) }
11
13
 
12
14
  describe '#get_board' do
13
15
  let(:invalid_row_size) { 11 }
14
16
  let(:valid_row_size) { 7 }
15
17
 
16
- it "displays an invalid row size error when given an invalid (outside 2-10) row size" do
17
- allow(io_interface).to receive(:get_row_size).and_return(invalid_row_size, valid_row_size)
18
+ it 'displays an invalid row size error when given a row size outside 2-10' do
19
+ allow(io).to receive(:get_row_size).and_return(invalid_row_size, valid_row_size)
18
20
 
19
- expect(io_interface).to receive(:invalid_row_size_error)
21
+ expect(io).to receive(:invalid_row_size_error)
20
22
  menu.get_board
21
23
  end
22
24
 
23
- it "only returns a row size once it receives a valid (2-10) row size" do
24
- allow(io_interface).to receive(:invalid_row_size_error)
25
- allow(io_interface).to receive(:get_row_size).and_return(invalid_row_size, valid_row_size)
25
+ it 'only returns a row size once it receives a valid (2-10) row size' do
26
+ allow(io).to receive(:invalid_row_size_error)
27
+ allow(io).to receive(:get_row_size).and_return(invalid_row_size, valid_row_size)
26
28
 
27
29
  board = menu.get_board
28
30
  expect(board.row_size).to eq(valid_row_size)
29
31
  end
30
32
  end
31
33
 
32
-
33
34
  describe '#get_players' do
34
- before(:each) do
35
- allow(io).to receive(:blue) { |argument| argument }
36
- allow(io).to receive(:red) { |argument| argument }
37
- end
38
-
39
- it "returns an array with a human (IO decider) player and a computer (AI decider) player" do
40
- first_token, second_token = "X", "O"
35
+ it 'returns an array with a human player and a computer player' do
36
+ first_token, second_token = 'X', 'O'
41
37
  difficulty = :medium
42
38
 
43
- allow(io_interface).to receive(:get_token).and_return(first_token, second_token)
44
- allow(io_interface).to receive(:get_difficulty).and_return(difficulty)
39
+ allow(io).to receive(:get_token).and_return(first_token, second_token)
40
+ allow(io).to receive(:get_difficulty).and_return(difficulty)
45
41
 
46
42
  human_player, computer_player = menu.get_players
47
- expect(human_player.decider).to be_a TicTacToes::IOInterface
48
- expect(computer_player.decider).to eq(TicTacToes::MediumAI)
43
+ expect(human_player.move_strategy).to be_a TicTacToes::MoveStrategies::Human
44
+ expect(computer_player.move_strategy).to eq(TicTacToes::MoveStrategies::MediumAI)
49
45
  end
50
46
 
51
47
  context 'when given an invalid (non-single-character) token' do
52
- let(:invalid_token) { "invalid" }
53
- let(:first_token) { "X" }
54
- let(:second_token) { "O" }
48
+ let(:invalid_token) { 'invalid' }
49
+ let(:first_token) { 'X' }
50
+ let(:second_token) { 'O' }
55
51
 
56
52
  before(:each) do
57
53
  valid_difficulty = :medium
58
- allow(io_interface).to receive(:get_difficulty) { valid_difficulty }
54
+ allow(io).to receive(:get_difficulty) { valid_difficulty }
59
55
  end
60
56
 
61
- it "displays an invalid token error" do
62
- allow(io_interface).to receive(:get_token).and_return(invalid_token, first_token, second_token)
57
+ it 'displays an invalid token error' do
58
+ allow(io).to receive(:get_token).and_return(invalid_token, first_token, second_token)
63
59
 
64
- expect(io_interface).to receive(:invalid_token_error)
60
+ expect(io).to receive(:invalid_token_error)
65
61
  menu.get_players
66
62
  end
67
63
 
68
- it "only returns an array of players (with correct tokens) once it receives a valid token" do
69
- allow(io_interface).to receive(:invalid_token_error)
70
- allow(io_interface).to receive(:get_token).and_return(invalid_token, first_token, second_token)
64
+ it 'only returns an array of players (with correct tokens) once it receives a valid token' do
65
+ allow(io).to receive(:invalid_token_error)
66
+ allow(io).to receive(:get_token).and_return(invalid_token, first_token, second_token)
71
67
 
72
68
  first_player, second_player = menu.get_players
73
69
  expect(first_player.token).to eq(first_token)
@@ -80,23 +76,23 @@ describe CommandLine::Menu do
80
76
  let(:valid_difficulty) { :medium }
81
77
 
82
78
  before(:each) do
83
- first_token, second_token = "X", "O"
84
- allow(io_interface).to receive(:get_token).and_return(first_token, second_token)
79
+ first_token, second_token = 'X', 'O'
80
+ allow(io).to receive(:get_token).and_return(first_token, second_token)
85
81
  end
86
82
 
87
- it "displays an invalid difficulty error" do
88
- allow(io_interface).to receive(:get_difficulty).and_return(invalid_difficulty, valid_difficulty)
83
+ it 'displays an invalid difficulty error' do
84
+ allow(io).to receive(:get_difficulty).and_return(invalid_difficulty, valid_difficulty)
89
85
 
90
- expect(io_interface).to receive(:invalid_difficulty_error)
86
+ expect(io).to receive(:invalid_difficulty_error)
91
87
  menu.get_players
92
88
  end
93
89
 
94
- it "only returns an array of players (with correct difficulty) once it receives a valid difficulty" do
95
- allow(io_interface).to receive(:invalid_difficulty_error)
96
- allow(io_interface).to receive(:get_difficulty).and_return(invalid_difficulty, valid_difficulty)
90
+ it 'only returns an array of players (with correct difficulty) once it receives a valid difficulty' do
91
+ allow(io).to receive(:invalid_difficulty_error)
92
+ allow(io).to receive(:get_difficulty).and_return(invalid_difficulty, valid_difficulty)
97
93
 
98
94
  computer_player = menu.get_players.last
99
- expect(computer_player.decider).to eq(TicTacToes::MediumAI)
95
+ expect(computer_player.move_strategy).to eq(TicTacToes::MoveStrategies::MediumAI)
100
96
  end
101
97
  end
102
98
  end
@@ -1,119 +1,41 @@
1
1
  require 'command_line/runner'
2
- require 'tic_tac_toes/board'
3
- require 'tic_tac_toes/history'
4
- require 'tic_tac_toes/spec_helper'
5
2
 
6
3
  describe CommandLine::Runner do
7
- let(:io_interface) { double("io interface",
8
- :draw_board => true,
9
- :thinking_notification => true,
10
- :game_over_notification => true) }
11
- let(:board) { TicTacToes::Board.new(row_size: 3) }
12
- let(:menu) { double("menu",
13
- :get_board => board,
14
- :get_players => true) }
15
- let(:rules) { double("rules",
16
- :game_over? => true,
17
- :determine_winner => "X") }
18
- let(:database_interface) { double("database interface", :record_game_history => true) }
19
- let(:history) { TicTacToes::History.new(database_interface) }
20
-
21
- let(:runner) { CommandLine::Runner.new(io_interface, menu, rules, history) }
22
-
23
-
24
4
  describe '#run' do
25
- it "gets a board and players" do
26
- expect(menu).to receive(:get_board)
27
- expect(menu).to receive(:get_players)
5
+ let(:game_state) { double(board: 'board', players: 'players', game_over: true) }
6
+
7
+ let(:io) { double(draw_board: true,
8
+ thinking_notification: true,
9
+ game_over_notification: true) }
10
+ let(:menu) { double(get_board: true,
11
+ get_players: true) }
12
+ let(:game_state) { double(board: 'board',
13
+ players: 'players',
14
+ game_over: true) }
15
+ let(:game_state_factory) { double(generate_game_state: game_state) }
16
+ let(:rules) { double(game_over?: true,
17
+ determine_winner: true) }
18
+
19
+ let(:runner) { CommandLine::Runner.new(io,
20
+ menu,
21
+ game_state_factory,
22
+ rules) }
23
+
24
+ it 'gets an initial game state' do
25
+ expect(game_state_factory).to receive(:generate_game_state)
28
26
  runner.run
29
27
  end
30
28
 
31
- it "has its history object record the board size" do
32
- runner.run
33
- expect(history.board_size).to eq(board.size)
34
- end
35
-
36
- it "takes turns until the game is over" do
29
+ it 'takes turns until the game is over' do
37
30
  allow(rules).to receive(:game_over?).and_return(false, true)
38
31
 
39
32
  expect(runner).to receive(:take_turn).once
40
33
  runner.run
41
34
  end
42
35
 
43
- it "ends the game when the game is over" do
36
+ it 'ends the game when the game is over' do
44
37
  expect(runner).to receive(:end_game)
45
38
  runner.run
46
39
  end
47
40
  end
48
-
49
-
50
- describe '#take_turn' do
51
- move = ["X", 0]
52
- let(:board) { double("board") }
53
- let(:first_player) { double("first player", make_move: move, needs_to_think: true) }
54
- let(:second_player) { double("second player", make_move: move, needs_to_think: false) }
55
- let(:players) { [first_player, second_player] }
56
-
57
- it "draws the board" do
58
- expect(io_interface).to receive(:draw_board)
59
- runner.take_turn(board, players)
60
- end
61
-
62
- it "displays a thinking notification if the current player needs to think" do
63
- expect(io_interface).to receive(:thinking_notification)
64
- runner.take_turn(board, players)
65
-
66
- expect(io_interface).not_to receive(:thinking_notification)
67
- runner.take_turn(board, players)
68
- end
69
-
70
- it "asks the first player to make a move" do
71
- expect(first_player).to receive(:make_move)
72
- runner.take_turn(board, players)
73
- end
74
-
75
- it "has its history object record the move" do
76
- runner.take_turn(board, players)
77
- expect(history.moves.first).to eql(move)
78
- end
79
-
80
- it "keeps track of the current player by rotating the players" do
81
- runner.take_turn(board, players)
82
- expect(second_player).to receive(:make_move)
83
- runner.take_turn(board, players)
84
- end
85
- end
86
-
87
-
88
- describe '#end_game' do
89
- let(:board) { double("board") }
90
- let(:players) { double("players") }
91
-
92
- it "draws the board" do
93
- expect(io_interface).to receive(:draw_board)
94
- runner.end_game(board, players)
95
- end
96
-
97
- it "determines the winner" do
98
- expect(rules).to receive(:determine_winner)
99
- runner.end_game(board, players)
100
- end
101
-
102
- it "displays the winner" do
103
- allow(rules).to receive(:determine_winner) { :winner }
104
-
105
- expect(io_interface).to receive(:game_over_notification).with(:winner)
106
- runner.end_game(board, players)
107
- end
108
-
109
- it "has its history object record the winner" do
110
- runner.end_game(board, players)
111
- expect(history.winner).to eq("X")
112
- end
113
-
114
- it "has its history object persist the game history" do
115
- expect(history).to receive(:persist)
116
- runner.end_game(board, players)
117
- end
118
- end
119
41
  end
@@ -1,6 +1,5 @@
1
1
  require 'database/pg_wrapper'
2
2
  require 'pg'
3
- require 'tic_tac_toes/spec_helper'
4
3
 
5
4
  describe Database::PGWrapper do
6
5
  database = "tic_tac_toes_test"
@@ -0,0 +1,15 @@
1
+ require 'tic_tac_toes/board'
2
+
3
+ module TestBoardGenerator
4
+ def self.generate(structure)
5
+ board_size = structure.count
6
+ row_size = Math.sqrt(board_size)
7
+ board = TicTacToes::Board.new(row_size: row_size)
8
+
9
+ structure.each_with_index do |player, index|
10
+ board.place(player, index)
11
+ end
12
+
13
+ board
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ require 'tic_tac_toes/board_factory'
2
+
3
+ describe TicTacToes::BoardFactory do
4
+ describe '#generate_board' do
5
+ it 'returns a board object generated from a row size' do
6
+ board_factory = TicTacToes::BoardFactory.new
7
+ row_size = 5
8
+
9
+ board = board_factory.generate_board(row_size)
10
+ expect(board.row_size).to eq(row_size)
11
+ end
12
+ end
13
+ end
@@ -1,4 +1,4 @@
1
- require 'tic_tac_toes/spec_helper'
1
+ require 'test_board_generator'
2
2
  require 'tic_tac_toes/board'
3
3
 
4
4
  describe TicTacToes::Board do
@@ -28,10 +28,9 @@ describe TicTacToes::Board do
28
28
 
29
29
  describe '#open_spaces' do
30
30
  it "returns an array of the board's nil spaces" do
31
- structure = [:X, :O, nil,
32
- :O, :O, :X,
33
- :X, :X, nil]
34
- board = generate_board(structure)
31
+ board = TestBoardGenerator.generate([:X, :O, nil,
32
+ :O, :O, :X,
33
+ :X, :X, nil])
35
34
  open_spaces = [2, 8]
36
35
 
37
36
  expect(board.open_spaces).to eql(open_spaces)
@@ -41,11 +40,10 @@ describe TicTacToes::Board do
41
40
 
42
41
  describe '#rows' do
43
42
  it "returns an array of row arrays based on the board's spaces" do
44
- structure = [ :X, :X, :X, :X,
45
- nil, nil, nil, nil,
46
- nil, nil, nil, nil,
47
- nil, nil, nil, nil]
48
- board = generate_board(structure)
43
+ board = TestBoardGenerator.generate([ :X, :X, :X, :X,
44
+ nil, nil, nil, nil,
45
+ nil, nil, nil, nil,
46
+ nil, nil, nil, nil])
49
47
  first_row = [:X, :X, :X, :X]
50
48
 
51
49
  expect(board.rows.size).to eq(4)
@@ -56,11 +54,10 @@ describe TicTacToes::Board do
56
54
 
57
55
  describe '#columns' do
58
56
  it "returns an array of column arrays based on the board's spaces" do
59
- structure = [:X, nil, nil, nil,
60
- :X, nil, nil, nil,
61
- :X, nil, nil, nil,
62
- :X, nil, nil, nil]
63
- board = generate_board(structure)
57
+ board = TestBoardGenerator.generate([:X, nil, nil, nil,
58
+ :X, nil, nil, nil,
59
+ :X, nil, nil, nil,
60
+ :X, nil, nil, nil])
64
61
  first_column = [:X, :X, :X, :X]
65
62
 
66
63
  expect(board.columns.size).to eq(4)
@@ -71,12 +68,11 @@ describe TicTacToes::Board do
71
68
 
72
69
  describe '#diagonals' do
73
70
  it "returns an array of diagonal arrays based on the board's spaces" do
74
- structure = [ :X, nil, nil, :O,
75
- nil, :X, :O, nil,
76
- nil, :O, :X, nil,
77
- :O, nil, nil, :X]
78
- board = generate_board(structure)
79
- back_diagonal = [:X, :X, :X, :X]
71
+ board = TestBoardGenerator.generate([ :X, nil, nil, :O,
72
+ nil, :X, :O, nil,
73
+ nil, :O, :X, nil,
74
+ :O, nil, nil, :X])
75
+ back_diagonal = [:X, :X, :X, :X]
80
76
  front_diagonal = [:O, :O, :O, :O]
81
77
 
82
78
  expect(board.diagonals.size).to eq(2)
@@ -93,10 +89,9 @@ describe TicTacToes::Board do
93
89
  end
94
90
 
95
91
  it "returns true if all spaces are non-nil" do
96
- structure = [:X, :O, :X,
97
- :O, :X, :O,
98
- :X, :O, :X]
99
- board = generate_board(structure)
92
+ board = TestBoardGenerator.generate([:X, :O, :X,
93
+ :O, :X, :O,
94
+ :X, :O, :X])
100
95
 
101
96
  expect(board.full?).to be true
102
97
  end
@@ -0,0 +1,15 @@
1
+ require 'tic_tac_toes/game_state_factory'
2
+
3
+ describe TicTacToes::GameStateFactory do
4
+ describe '#generate_game_state' do
5
+ it 'returns a game state object generated from a board object and player array' do
6
+ history = double(record_board_size: true)
7
+ game_state_factory = TicTacToes::GameStateFactory.new(history)
8
+ board, players = double(size: 3), double
9
+
10
+ game_state = game_state_factory.generate_game_state(board, players)
11
+ expect(game_state.board).to eq(board)
12
+ expect(game_state.players).to eq(players)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,66 @@
1
+ require 'tic_tac_toes/game_state'
2
+
3
+ describe TicTacToes::GameState do
4
+ describe '@initialize' do
5
+ it "records its board's size" do
6
+ size = 5
7
+ board = double(size: size)
8
+ history = double
9
+
10
+ expect(history).to receive(:record_board_size).with(size)
11
+ TicTacToes::GameState.new(board, 'players', history)
12
+ end
13
+ end
14
+
15
+ describe '#current_player' do
16
+ it 'returns the first item of its players array' do
17
+ history = double(record_board_size: true)
18
+ players = ['first_player', 'second_player']
19
+ game_state = TicTacToes::GameState.new('board', players, history)
20
+
21
+ current_player = game_state.current_player
22
+ expect(current_player).to eq('first_player')
23
+ end
24
+ end
25
+
26
+ describe '#turn_over' do
27
+ it 'records the last move' do
28
+ move = double
29
+ players = double(rotate!: true)
30
+ history = double(record_board_size: true)
31
+ game_state = TicTacToes::GameState.new('board', players, history)
32
+
33
+ expect(history).to receive(:record_move).with(move)
34
+ game_state.turn_over(move)
35
+ end
36
+
37
+ it 'rotates its player array' do
38
+ players = ['first_player', 'second_player']
39
+ history = double(record_board_size: true, record_move: true)
40
+ game_state = TicTacToes::GameState.new('board', players, history)
41
+
42
+ game_state.turn_over('move')
43
+ expect(game_state.current_player).to eq('second_player')
44
+ end
45
+ end
46
+
47
+ describe '#game_over' do
48
+ it 'records the winner' do
49
+ winner = double
50
+ history = double(record_board_size: true, persist: true)
51
+ game_state = TicTacToes::GameState.new('board', 'players', history)
52
+
53
+ expect(history).to receive(:record_winner).with(winner)
54
+ game_state.game_over(winner)
55
+ end
56
+
57
+ it 'persists its history' do
58
+ winner = double
59
+ history = double(record_board_size: true, record_winner: true)
60
+ game_state = TicTacToes::GameState.new('board', 'players', history)
61
+
62
+ expect(history).to receive(:persist)
63
+ game_state.game_over(winner)
64
+ end
65
+ end
66
+ end
@@ -1,9 +1,8 @@
1
- require 'tic_tac_toes/spec_helper'
2
1
  require 'tic_tac_toes/history'
3
2
 
4
3
  describe TicTacToes::History do
5
- let(:database_interface) { double("database interface", :record_game_history => true) }
6
- let(:history) { TicTacToes::History.new(database_interface) }
4
+ let(:database_wrapper) { double("database wrapper", :record_game_history => true) }
5
+ let(:history) { TicTacToes::History.new(database_wrapper) }
7
6
 
8
7
  describe '#record_board_size' do
9
8
  it "records the passed board size" do
@@ -34,7 +33,7 @@ describe TicTacToes::History do
34
33
 
35
34
  describe '#persist' do
36
35
  it "sends the history instance to its database interface for storage" do
37
- expect(database_interface).to receive(:record_game_history).with history
36
+ expect(database_wrapper).to receive(:record_game_history).with history
38
37
  history.persist
39
38
  end
40
39
  end
@@ -0,0 +1,163 @@
1
+ require 'tic_tac_toes/board'
2
+ require 'tic_tac_toes/io'
3
+ require 'tic_tac_toes/strings'
4
+
5
+ describe TicTacToes::IO do
6
+ let(:strings) { TicTacToes::Strings }
7
+ let(:prompt) { double("prompt", solicit_input: 0, display: true, display_red: true) }
8
+ let(:io) { TicTacToes::IO.new(prompt) }
9
+
10
+ describe '#get_row_size' do
11
+ it "displays a row size solicitation" do
12
+ expect(io).to receive(:row_size_solicitation)
13
+ io.get_row_size
14
+ end
15
+
16
+ context 'when given not-integer-like input' do
17
+ let(:not_integer_like) { "string" }
18
+ let(:integer_like) { "100" }
19
+
20
+ it "displays a not an integer error" do
21
+ allow(prompt).to receive(:solicit_input).and_return(not_integer_like, integer_like)
22
+
23
+ expect(io).to receive(:not_an_integer_error).once
24
+ io.get_row_size
25
+ end
26
+
27
+ it "only returns a row size (converted to integer) once it gets integer-like input" do
28
+ allow(prompt).to receive(:solicit_input).and_return(not_integer_like, integer_like)
29
+
30
+ expect(io.get_row_size).to eq(100)
31
+ end
32
+ end
33
+ end
34
+
35
+
36
+ describe '#get_token' do
37
+ let(:player) { double("player") }
38
+
39
+ it "displays a token solicitation with the name of the player whose token is to be set" do
40
+ expect(io).to receive(:token_solicitation).with(player)
41
+ io.get_token(player)
42
+ end
43
+
44
+ it "returns the user input" do
45
+ token = "X"
46
+ allow(prompt).to receive(:solicit_input) { token }
47
+
48
+ expect(io.get_token(player)).to equal(token)
49
+ end
50
+ end
51
+
52
+
53
+ describe '#get_difficulty' do
54
+ let(:difficulty) { "HARD" }
55
+
56
+ it "displays a difficulty solicitation" do
57
+ allow(prompt).to receive(:solicit_input) { difficulty }
58
+
59
+ expect(io).to receive(:difficulty_solicitation)
60
+ io.get_difficulty
61
+ end
62
+
63
+ it "returns the user input (downcased and converted into a symbol)" do
64
+ allow(prompt).to receive(:solicit_input) { difficulty }
65
+
66
+ expect(io.get_difficulty).to equal(:hard)
67
+ end
68
+ end
69
+
70
+
71
+ describe '#draw_board' do
72
+ it "displays a board string" do
73
+ board = TicTacToes::Board.new
74
+ board_string = strings.board(board)
75
+
76
+ expect(prompt).to receive(:display).with(board_string)
77
+ io.draw_board(board)
78
+ end
79
+ end
80
+
81
+
82
+ describe '#invalid_row_size_error' do
83
+ it "displays a red invalid row size message" do
84
+ expect(prompt).to receive(:display_red).with(strings::INVALID_ROW_SIZE)
85
+ io.invalid_row_size_error
86
+ end
87
+ end
88
+
89
+
90
+ describe '#invalid_token_error' do
91
+ it "displays a red invalid token message" do
92
+ expect(prompt).to receive(:display_red).with(strings::INVALID_TOKEN)
93
+ io.invalid_token_error
94
+ end
95
+ end
96
+
97
+
98
+ describe '#invalid_difficulty_error' do
99
+ it "displays a red invalid difficulty message" do
100
+ expect(prompt).to receive(:display_red).with(strings::INVALID_DIFFICULTY)
101
+ io.invalid_difficulty_error
102
+ end
103
+ end
104
+
105
+
106
+ describe '#invalid_move_error' do
107
+ it "displays a red invalid move message" do
108
+ expect(prompt).to receive(:display_red).with(strings::INVALID_MOVE)
109
+ io.invalid_move_error
110
+ end
111
+ end
112
+
113
+
114
+ describe '#thinking_notification' do
115
+ it "displays a red thinking message" do
116
+ expect(prompt).to receive(:display_red).with(strings::THINKING)
117
+ io.thinking_notification
118
+ end
119
+ end
120
+
121
+
122
+ describe '#game_over_notification' do
123
+ it "displays a game over message with the name of the winner" do
124
+ winner = :X
125
+ game_over_message = strings.game_over_notification(winner)
126
+
127
+ expect(prompt).to receive(:display).with(game_over_message)
128
+ io.game_over_notification(winner)
129
+ end
130
+ end
131
+
132
+
133
+ describe '#move_solicitation' do
134
+ it "displays a move solicitation message" do
135
+ expect(prompt).to receive(:display).with(strings::MOVE_SOLICITATION)
136
+ io.move_solicitation
137
+ end
138
+ end
139
+
140
+
141
+ describe '#not_an_integer_error' do
142
+ it "displays a red not an integer message" do
143
+ expect(prompt).to receive(:display_red).with(strings::NOT_AN_INTEGER)
144
+ io.not_an_integer_error
145
+ end
146
+ end
147
+
148
+
149
+ describe '#red' do
150
+ it "calls its IO's red method with the passed message" do
151
+ expect(io).to receive(:red).with("message")
152
+ io.red("message")
153
+ end
154
+ end
155
+
156
+
157
+ describe '#blue' do
158
+ it "calls its IO's blue method with the passed message" do
159
+ expect(io).to receive(:blue).with("message")
160
+ io.blue("message")
161
+ end
162
+ end
163
+ end