ttt-core 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.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +36 -0
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +2 -0
  7. data/Gemfile +8 -0
  8. data/Gemfile.lock +61 -0
  9. data/README.md +29 -0
  10. data/Rakefile +8 -0
  11. data/bin/run.sh +21 -0
  12. data/lib/ai_player.rb +117 -0
  13. data/lib/board.rb +87 -0
  14. data/lib/board_factory.rb +8 -0
  15. data/lib/game.rb +27 -0
  16. data/lib/player.rb +16 -0
  17. data/lib/player_factory.rb +38 -0
  18. data/lib/player_options.rb +48 -0
  19. data/lib/player_symbols.rb +16 -0
  20. data/lib/replay_option.rb +3 -0
  21. data/lib/ttt-core/version.rb +3 -0
  22. data/spec/ai_player_spec.rb +143 -0
  23. data/spec/board_factory_spec.rb +10 -0
  24. data/spec/board_spec.rb +125 -0
  25. data/spec/game_spec.rb +58 -0
  26. data/spec/player_options_spec.rb +33 -0
  27. data/spec/player_symbols_spec.rb +32 -0
  28. data/spec/replay_option_spec.rb +8 -0
  29. data/spec/spec_helper.rb +107 -0
  30. data/ttt-core-0.0.1/.gitignore +36 -0
  31. data/ttt-core-0.0.1/.rspec +2 -0
  32. data/ttt-core-0.0.1/.ruby-gemset +1 -0
  33. data/ttt-core-0.0.1/.ruby-version +1 -0
  34. data/ttt-core-0.0.1/.travis.yml +2 -0
  35. data/ttt-core-0.0.1/Gemfile +10 -0
  36. data/ttt-core-0.0.1/README.md +21 -0
  37. data/ttt-core-0.0.1/Rakefile +7 -0
  38. data/ttt-core-0.0.1/bin/run.sh +21 -0
  39. data/ttt-core-0.0.1/lib/ai_player.rb +117 -0
  40. data/ttt-core-0.0.1/lib/board.rb +87 -0
  41. data/ttt-core-0.0.1/lib/board_factory.rb +8 -0
  42. data/ttt-core-0.0.1/lib/game.rb +27 -0
  43. data/ttt-core-0.0.1/lib/player.rb +16 -0
  44. data/ttt-core-0.0.1/lib/player_factory.rb +38 -0
  45. data/ttt-core-0.0.1/lib/player_options.rb +48 -0
  46. data/ttt-core-0.0.1/lib/player_symbols.rb +16 -0
  47. data/ttt-core-0.0.1/lib/replay_option.rb +3 -0
  48. data/ttt-core-0.0.1/spec/ai_player_spec.rb +143 -0
  49. data/ttt-core-0.0.1/spec/board_factory_spec.rb +10 -0
  50. data/ttt-core-0.0.1/spec/board_spec.rb +125 -0
  51. data/ttt-core-0.0.1/spec/game_spec.rb +58 -0
  52. data/ttt-core-0.0.1/spec/player_options_spec.rb +33 -0
  53. data/ttt-core-0.0.1/spec/player_symbols_spec.rb +32 -0
  54. data/ttt-core-0.0.1/spec/replay_option_spec.rb +8 -0
  55. data/ttt-core-0.0.1/spec/spec_helper.rb +107 -0
  56. data/ttt-core.gemspec +22 -0
  57. metadata +150 -0
@@ -0,0 +1,143 @@
1
+ require 'ai_player'
2
+ require 'board'
3
+
4
+ RSpec.describe AiPlayer do
5
+ let(:ai_player) { AiPlayer.new(PlayerSymbols::X) }
6
+
7
+ it "has a player symbol" do
8
+ expect(ai_player.game_symbol).to eq(PlayerSymbols::X)
9
+ end
10
+
11
+ it "has ready state" do
12
+ expect(ai_player.ready?).to be true
13
+ end
14
+
15
+ it "scores zero when a draw is made" do
16
+ draw_board = Board.new([PlayerSymbols::X, PlayerSymbols::O, PlayerSymbols::X, PlayerSymbols::X, PlayerSymbols::O, PlayerSymbols::O, PlayerSymbols::O, PlayerSymbols::X, PlayerSymbols::X])
17
+ expect(ai_player.minimax(draw_board, true, draw_board.vacant_indices.size, -2, 2).first.first).to be (0 + draw_board.vacant_indices.size)
18
+ end
19
+
20
+ it "scores one if computer wins" do
21
+ winning_board = Board.new([PlayerSymbols::X, PlayerSymbols::X, PlayerSymbols::X, nil, nil, PlayerSymbols::O, PlayerSymbols::O, nil, nil])
22
+
23
+ expect(ai_player.minimax(winning_board, true, winning_board.vacant_indices.size, -2, 2).first.first).to be(1 + winning_board.vacant_indices.size)
24
+ end
25
+
26
+ it "scores negative one if opponent wins" do
27
+ winning_board = Board.new([PlayerSymbols::O, PlayerSymbols::O, PlayerSymbols::O, nil, nil, PlayerSymbols::X, PlayerSymbols::X, nil, nil])
28
+
29
+ expect(ai_player.minimax(winning_board, true, winning_board.vacant_indices.size, -2, 2).first.first).to be(-1 - winning_board.vacant_indices.size)
30
+ end
31
+
32
+ it "takes a winning move on top row" do
33
+ winning_move_on_top_row = Board.new([PlayerSymbols::X, nil, PlayerSymbols::X, nil, nil, PlayerSymbols::O, PlayerSymbols::O, nil, nil])
34
+
35
+ move = ai_player.choose_move(winning_move_on_top_row)
36
+ expect(move).to eq(1)
37
+ end
38
+
39
+ it "takes a winning move on middle row" do
40
+ winning_move_on_middle_row = Board.new([PlayerSymbols::O, nil, nil, PlayerSymbols::X, nil, PlayerSymbols::X, PlayerSymbols::O, nil, PlayerSymbols::O])
41
+
42
+ move = ai_player.choose_move(winning_move_on_middle_row)
43
+ expect(move).to eq(4)
44
+ end
45
+
46
+ it "takes a winning move on bottom row" do
47
+ winning_move_on_bottom_row = Board.new([PlayerSymbols::O, nil, PlayerSymbols::O, PlayerSymbols::O, nil, PlayerSymbols::X, nil, PlayerSymbols::X, PlayerSymbols::X])
48
+
49
+ move = ai_player.choose_move(winning_move_on_bottom_row)
50
+ expect(move).to eq(6)
51
+ end
52
+
53
+ it "takes a winning move on left column" do
54
+ winning_move_on_left_column = Board.new([PlayerSymbols::X, PlayerSymbols::O, nil, nil, nil, nil, PlayerSymbols::X, nil, PlayerSymbols::O])
55
+
56
+ move = ai_player.choose_move(winning_move_on_left_column)
57
+ expect(move).to eq(3)
58
+ end
59
+
60
+ it "takes a winning move on middle column" do
61
+ winning_move_on_middle_column = Board.new([nil, PlayerSymbols::X, PlayerSymbols::O, PlayerSymbols::O, PlayerSymbols::X, nil, nil, nil, nil])
62
+
63
+ move = ai_player.choose_move(winning_move_on_middle_column)
64
+ expect(move).to eq(7)
65
+ end
66
+
67
+ it "takes a winning move on right column" do
68
+ winning_move_on_right_column = Board.new([nil, PlayerSymbols::O, PlayerSymbols::X, nil, PlayerSymbols::O, nil, nil, nil, PlayerSymbols::X])
69
+
70
+ move = ai_player.choose_move(winning_move_on_right_column)
71
+ expect(move).to eq(5)
72
+ end
73
+
74
+ it "takes a winning move on first diagonal" do
75
+ winning_move_on_first_diagonal = Board.new([PlayerSymbols::X, nil, PlayerSymbols::O, nil, nil, PlayerSymbols::O, nil, nil, PlayerSymbols::X])
76
+
77
+ move = ai_player.choose_move(winning_move_on_first_diagonal)
78
+ expect(move).to eq(4)
79
+ end
80
+
81
+ it "takes a winning move on second diagonal" do
82
+ winning_move_on_second_diagonal = Board.new([PlayerSymbols::O, nil, nil, nil, PlayerSymbols::X, nil, PlayerSymbols::X, PlayerSymbols::O, nil])
83
+
84
+ move = ai_player.choose_move(winning_move_on_second_diagonal)
85
+ expect(move).to eq(2)
86
+ end
87
+
88
+ it "takes a blocking move on top row" do
89
+ blocking_move_on_top_row = Board.new([PlayerSymbols::O, nil, PlayerSymbols::O, PlayerSymbols::X, nil, nil, nil, nil, PlayerSymbols::X])
90
+
91
+ move = ai_player.choose_move(blocking_move_on_top_row)
92
+ expect(move).to eq(1)
93
+ end
94
+
95
+ it "takes a blocking move on middle row" do
96
+ blocking_move_on_middle_row = Board.new([PlayerSymbols::X, PlayerSymbols::O, PlayerSymbols::X, PlayerSymbols::O, PlayerSymbols::O, nil, nil, PlayerSymbols::X, nil])
97
+
98
+ move = ai_player.choose_move(blocking_move_on_middle_row)
99
+ expect(move).to eq(5)
100
+ end
101
+
102
+ it "takes a blocking move on bottom row" do
103
+ blocking_move_on_bottom_row = Board.new([PlayerSymbols::X, PlayerSymbols::O, PlayerSymbols::X, nil, nil, PlayerSymbols::X, nil, PlayerSymbols::O, PlayerSymbols::O])
104
+
105
+ move = ai_player.choose_move(blocking_move_on_bottom_row)
106
+ expect(move).to eq(6)
107
+ end
108
+
109
+ it "takes a blocking move on left column" do
110
+ blocking_move_on_left_column = Board.new([PlayerSymbols::O, nil, nil, nil, nil, PlayerSymbols::X, PlayerSymbols::O, PlayerSymbols::X, nil])
111
+
112
+ move = ai_player.choose_move(blocking_move_on_left_column)
113
+ expect(move).to eq(3)
114
+ end
115
+
116
+ it "takes a blocking move on middle column" do
117
+ blocking_move_on_middle_column = Board.new([nil, PlayerSymbols::O, nil, PlayerSymbols::X,nil, nil, nil, PlayerSymbols::O, nil])
118
+
119
+ move = ai_player.choose_move(blocking_move_on_middle_column)
120
+ expect(move).to eq(4)
121
+ end
122
+
123
+ it "takes a blocking move on right column" do
124
+ blocking_move_on_right_column = Board.new([nil, nil, PlayerSymbols::O, nil, nil, PlayerSymbols::O, nil, PlayerSymbols::X, nil])
125
+
126
+ move = ai_player.choose_move(blocking_move_on_right_column)
127
+ expect(move).to eq(8)
128
+ end
129
+
130
+ it "takes a blocking move on first diagonal" do
131
+ blocking_move_on_first_diagonal = Board.new([PlayerSymbols::O, PlayerSymbols::X, nil, nil,nil, nil, nil, nil, PlayerSymbols::O])
132
+
133
+ move = ai_player.choose_move(blocking_move_on_first_diagonal)
134
+ expect(move).to eq(4)
135
+ end
136
+
137
+ it "takes a blocking move on second diagonal" do
138
+ blocking_move_on_second_diagonal = Board.new([nil, nil, PlayerSymbols::O, nil, nil, nil, PlayerSymbols::O, PlayerSymbols::X, nil])
139
+
140
+ move = ai_player.choose_move(blocking_move_on_second_diagonal)
141
+ expect(move).to eq(4)
142
+ end
143
+ end
@@ -0,0 +1,10 @@
1
+ require 'board_factory'
2
+
3
+ RSpec.describe BoardFactory do
4
+ let(:board_factory) { BoardFactory.new }
5
+
6
+ it "creates 3x3 board " do
7
+ board = board_factory.create_board
8
+ expect(board.grid_for_display.size).to be 3
9
+ end
10
+ end
@@ -0,0 +1,125 @@
1
+ require 'board'
2
+ require 'player_symbols'
3
+
4
+ RSpec.describe Board do
5
+ X = PlayerSymbols::X
6
+ O = PlayerSymbols::O
7
+
8
+ let (:board) {Board.new}
9
+
10
+ it "is empty on initialisation" do
11
+ expect(board.empty?).to be true
12
+ end
13
+
14
+ it "is not empty when all slots are occupied" do
15
+ full_board = Board.new([X, O, X, O, X, O, X, X, O])
16
+ expect(full_board.empty?).to be false
17
+ end
18
+
19
+ it "returns the current grid formation" do
20
+ board = Board.new([nil, nil, nil, nil, X, O, nil, nil, nil])
21
+ expect(board.grid_for_display).to eq([[nil, nil, nil], [nil, X, O], [nil, nil, nil]])
22
+ end
23
+
24
+ it "can get symbol at given position" do
25
+ board = Board.new([nil, nil, nil, nil, X, O, nil, nil, nil])
26
+ expect(board.get_symbol_at(4)).to be :X
27
+ end
28
+
29
+ it "can be updated at a given position" do
30
+ updated_board = board.make_move(1, X)
31
+ expect(updated_board.get_symbol_at(1)).to eq(X)
32
+ end
33
+
34
+ it "has free spaces" do
35
+ expect(board.free_spaces?).to be true
36
+ end
37
+
38
+ it "has no free spaces when all slots are occupied" do
39
+ full_board = Board.new([X, O, X, O, X, O, X, X, O])
40
+ expect(full_board.free_spaces?).to be false
41
+ end
42
+
43
+ it "has no winning combination" do
44
+ winning_board = Board.new([O, X, X, nil, nil, nil, nil, nil, nil])
45
+ expect(winning_board.winning_combination?).to be false
46
+ end
47
+
48
+ it "has winning combination of X in top row" do
49
+ winning_board = Board.new([X, X, X, nil, nil, nil, nil, nil, nil])
50
+ expect(winning_board.winning_combination?).to be true
51
+ end
52
+
53
+ it "has winning combination of X in middle row" do
54
+ winning_board = Board.new([nil, nil, nil, X, X, X, nil, nil, nil])
55
+ expect(winning_board.winning_combination?).to be true
56
+ end
57
+
58
+ it "has winning combination of X in bottom row" do
59
+ winning_board = Board.new([nil, nil, nil, nil, nil, nil, X, X, X])
60
+ expect(winning_board.winning_combination?).to be true
61
+ end
62
+
63
+ it "has winning combination of X in left column" do
64
+ winning_board = Board.new([X, nil, nil, X, nil, nil, X, nil, nil])
65
+ expect(winning_board.winning_combination?).to be true
66
+ end
67
+
68
+ it "has winning combination of X in middle column" do
69
+ winning_board = Board.new([nil, X, nil, nil, X, nil, nil, X, nil])
70
+ expect(winning_board.winning_combination?).to be true
71
+ end
72
+
73
+ it "has winning combination of X in right column" do
74
+ winning_board = Board.new([nil, nil, X, nil, nil, X, nil, nil, X])
75
+ expect(winning_board.winning_combination?).to be true
76
+ end
77
+
78
+ it "has winning combination of X in first diagonal" do
79
+ winning_board = Board.new([X, nil, nil, nil, X, nil, nil, nil, X])
80
+ expect(winning_board.winning_combination?).to be true
81
+ end
82
+
83
+ it "has winning combination of X in second diagonal" do
84
+ winning_board = Board.new([nil, nil, X, nil, X, nil, X, nil, nil])
85
+ expect(winning_board.winning_combination?).to be true
86
+ end
87
+
88
+ it "has winning combination of O in top row" do
89
+ winning_board = Board.new([O, O, O, nil, nil, nil, nil, nil, nil])
90
+ expect(winning_board.winning_combination?).to be true
91
+ end
92
+
93
+ it "has winning combination of O in left column" do
94
+ winning_board = Board.new([O, nil, nil, O, nil, nil, O, nil, nil])
95
+ expect(winning_board.winning_combination?).to be true
96
+ end
97
+
98
+ it "has winning combination of O in first diagonal" do
99
+ winning_board = Board.new([O, nil, nil, nil, O, nil, nil, nil, O])
100
+ expect(winning_board.winning_combination?).to be true
101
+ end
102
+
103
+ it "has winning symbol X" do
104
+ winning_board = Board.new([X, X, X, nil, nil, nil, nil, nil, nil])
105
+ expect(winning_board.winning_symbol).to be X
106
+ end
107
+
108
+ it "has winning symbol O" do
109
+ winning_board = Board.new([O, O, O, nil, nil, nil, nil, nil, nil])
110
+ expect(winning_board.winning_symbol).to be O
111
+ end
112
+
113
+ it "has no winning symbol" do
114
+ expect(board.winning_symbol).to be nil
115
+ end
116
+
117
+ it "gives all vacant indices on an empty board" do
118
+ expect(board.vacant_indices).to include(0, 1, 2, 3, 4, 5, 6, 7, 8)
119
+ end
120
+
121
+ it "gives all vacant indices on a board with moves" do
122
+ board = Board.new([X, nil, O, nil, nil, nil, nil, nil, nil])
123
+ expect(board.vacant_indices).not_to include(0, 2)
124
+ end
125
+ end
data/spec/game_spec.rb ADDED
@@ -0,0 +1,58 @@
1
+ require 'board'
2
+ require 'game'
3
+ require 'player'
4
+ require 'player_symbols'
5
+
6
+ RSpec.describe Game do
7
+ let(:player_x_spy) { instance_double(FakePlayer).as_null_object }
8
+ let(:player_o_spy) { instance_double(FakePlayer).as_null_object }
9
+
10
+ it "continues until player is not ready" do
11
+ allow(player_x_spy).to receive(:ready?).and_return(true, false)
12
+ allow(player_o_spy).to receive(:ready?).and_return(true)
13
+
14
+ expect(player_x_spy).to receive(:choose_move).exactly(1).times.and_return(2)
15
+ expect(player_o_spy).to receive(:choose_move).exactly(1).times.and_return(8)
16
+
17
+ Game.new(Board.new, [player_x_spy, player_o_spy]).play
18
+ end
19
+
20
+ it "players take turn until there is no space on board" do
21
+ expect(player_x_spy).to receive(:choose_move).exactly(5).times.and_return(0, 1, 4, 5, 6)
22
+ expect(player_o_spy).to receive(:choose_move).exactly(4).times.and_return(2, 3, 7, 8)
23
+
24
+ Game.new(Board.new, [player_x_spy, player_o_spy]).play
25
+
26
+ end
27
+
28
+ it "game ends when a winning combination is formed" do
29
+ allow(player_x_spy).to receive(:choose_move).once.and_return(2)
30
+ allow(player_x_spy).to receive(:game_symbol).and_return(PlayerSymbols::X)
31
+
32
+ board = Board.new([PlayerSymbols::X, PlayerSymbols::X, nil, PlayerSymbols::O, nil, nil, nil, nil, nil])
33
+ updated_board = Game.new(board, [player_x_spy, player_o_spy]).play
34
+
35
+ expect(updated_board.get_symbol_at(2)).to be (PlayerSymbols::X)
36
+ expect(player_o_spy).to_not have_received(:choose_move)
37
+ end
38
+
39
+ it "game ends when there are no free spaces on the board" do
40
+ full_board = Board.new([PlayerSymbols::X, PlayerSymbols::X, PlayerSymbols::O, PlayerSymbols::O, PlayerSymbols::O, PlayerSymbols::X, PlayerSymbols::X, PlayerSymbols::O, PlayerSymbols::X])
41
+ game = Game.new(full_board, [player_x_spy, player_o_spy]).play
42
+
43
+ expect(player_o_spy).to_not have_received(:choose_move)
44
+ expect(player_x_spy).to_not have_received(:choose_move)
45
+ end
46
+ end
47
+
48
+ class FakePlayer
49
+
50
+ include Player
51
+
52
+ def choose_move(board)
53
+ end
54
+
55
+ def ready?
56
+ end
57
+ end
58
+
@@ -0,0 +1,33 @@
1
+ require 'player_options'
2
+
3
+ RSpec.describe PlayerOptions do
4
+
5
+ it "has player option Human vs Human" do
6
+ expect(PlayerOptions::HUMAN_VS_HUMAN).to eq ("Human vs Human")
7
+ end
8
+
9
+ it "has player option Human vs Ai" do
10
+ expect(PlayerOptions::HUMAN_VS_AI).to eq ("Human vs Ai")
11
+ end
12
+
13
+ it "has player option Ai vs Human" do
14
+ expect(PlayerOptions::AI_VS_HUMAN).to eq ("Ai vs Human")
15
+ end
16
+
17
+ it "has valid player option ids" do
18
+ expect(PlayerOptions::valid_ids).to eq ([1, 2, 3])
19
+ end
20
+
21
+ it "gets player type for id" do
22
+ expect(PlayerOptions::get_player_type_for_id(1)).to eq (PlayerOptions::HUMAN_VS_HUMAN)
23
+ end
24
+
25
+ it "gets player options for display" do
26
+ expect(PlayerOptions::display_player_options).to eq("(1) Human vs Human, (2) Human vs Ai, (3) Ai vs Human" )
27
+ end
28
+
29
+ it "gets all player options" do
30
+ all_expected_types = { 1 => "Human vs Human", 2=> "Human vs Ai", 3 => "Ai vs Human" }
31
+ expect(PlayerOptions::all).to eq(all_expected_types)
32
+ end
33
+ end
@@ -0,0 +1,32 @@
1
+ require 'player_symbols'
2
+
3
+ RSpec.describe PlayerSymbols do
4
+
5
+ it "has player symbol X" do
6
+ expect(PlayerSymbols::X).to be :X
7
+ end
8
+
9
+ it "has player symbol O" do
10
+ expect(PlayerSymbols::O).to be :O
11
+ end
12
+
13
+ it "finds opponent of X" do
14
+ expect(PlayerSymbols::opponent(PlayerSymbols::X)).to be :O
15
+ end
16
+
17
+ it "finds opponent of O" do
18
+ expect(PlayerSymbols::opponent(PlayerSymbols::O)).to be :X
19
+ end
20
+
21
+ it "all player symbols as strings" do
22
+ expect(PlayerSymbols::all).to eq ["X", "O"]
23
+ end
24
+
25
+ it "converts X to player symbol" do
26
+ expect(PlayerSymbols::to_symbol("X")).to eq :X
27
+ end
28
+
29
+ it "converts O to player symbol" do
30
+ expect(PlayerSymbols::to_symbol("O")).to eq :O
31
+ end
32
+ end
@@ -0,0 +1,8 @@
1
+ require 'replay_option'
2
+
3
+ RSpec.describe ReplayOption do
4
+
5
+ it "has replay option of Y" do
6
+ expect(ReplayOption::Y.include?("Y")).to be true
7
+ end
8
+ end
@@ -0,0 +1,107 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
4
+ # this file to always be loaded, without a need to explicitly require it in any
5
+ # files.
6
+ #
7
+ # Given that it is always loaded, you are encouraged to keep this file as
8
+ # light-weight as possible. Requiring heavyweight dependencies from this file
9
+ # will add to the boot time of your test suite on EVERY test run, even for an
10
+ # individual file that may not need all of that loaded. Instead, consider making
11
+ # a separate helper file that requires the additional dependencies and performs
12
+ # the additional setup, and require it from the spec files that actually need
13
+ # it.
14
+ #
15
+ # The `.rspec` file also contains a few flags that are not defaults but that
16
+ # users commonly want.
17
+ #
18
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
19
+
20
+ require 'simplecov'
21
+ require 'coveralls'
22
+
23
+ Coveralls.wear!
24
+ SimpleCov.minimum_coverage 100
25
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
26
+ SimpleCov::Formatter::HTMLFormatter,
27
+ Coveralls::SimpleCov::Formatter
28
+ ])
29
+ RSpec.configure do |config|
30
+ # rspec-expectations config goes here. You can use an alternate
31
+ # assertion/expectation library such as wrong or the stdlib/minitest
32
+ # assertions if you prefer.
33
+ config.expect_with :rspec do |expectations|
34
+ # This option will default to `true` in RSpec 4. It makes the `description`
35
+ # and `failure_message` of custom matchers include text for helper methods
36
+ # defined using `chain`, e.g.:
37
+ # be_bigger_than(2).and_smaller_than(4).description
38
+ # # => "be bigger than 2 and smaller than 4"
39
+ # ...rather than:
40
+ # # => "be bigger than 2"
41
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
42
+ end
43
+
44
+ # rspec-mocks config goes here. You can use an alternate test double
45
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
46
+ config.mock_with :rspec do |mocks|
47
+ # Prevents you from mocking or stubbing a method that does not exist on
48
+ # a real object. This is generally recommended, and will default to
49
+ # `true` in RSpec 4.
50
+ mocks.verify_partial_doubles = true
51
+ mocks.verify_doubled_constant_names = true
52
+ end
53
+
54
+ # The settings below are suggested to provide a good initial experience
55
+ # with RSpec, but feel free to customize to your heart's content.
56
+ =begin
57
+ # These two settings work together to allow you to limit a spec run
58
+ # to individual examples or groups you care about by tagging them with
59
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
60
+ # get run.
61
+ config.filter_run :focus
62
+ config.run_all_when_everything_filtered = true
63
+
64
+ # Allows RSpec to persist some state between runs in order to support
65
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
66
+ # you configure your source control system to ignore this file.
67
+ config.example_status_persistence_file_path = "spec/examples.txt"
68
+
69
+ # Limits the available syntax to the non-monkey patched syntax that is
70
+ # recommended. For more details, see:
71
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
72
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
73
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
74
+ config.disable_monkey_patching!
75
+
76
+ # This setting enables warnings. It's recommended, but in some cases may
77
+ # be too noisy due to issues in dependencies.
78
+ config.warnings = true
79
+
80
+ # Many RSpec users commonly either run the entire suite or an individual
81
+ # file, and it's useful to allow more verbose output when running an
82
+ # individual spec file.
83
+ if config.files_to_run.one?
84
+ # Use the documentation formatter for detailed output,
85
+ # unless a formatter has already been configured
86
+ # (e.g. via a command-line flag).
87
+ config.default_formatter = 'doc'
88
+ end
89
+
90
+ # Print the 10 slowest examples and example groups at the
91
+ # end of the spec run, to help surface which specs are running
92
+ # particularly slow.
93
+ config.profile_examples = 10
94
+
95
+ # Run specs in random order to surface order dependencies. If you find an
96
+ # order dependency and want to debug it, you can fix the order by providing
97
+ # the seed, which is printed after each run.
98
+ # --seed 1234
99
+ config.order = :random
100
+
101
+ # Seed global randomization in this process using the `--seed` CLI option.
102
+ # Setting this allows you to use `--seed` to deterministically reproduce
103
+ # test failures related to randomization by passing the same `--seed` value
104
+ # as the one that triggered the failure.
105
+ Kernel.srand config.seed
106
+ =end
107
+ end
@@ -0,0 +1,36 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+ .coveralls.yml
12
+
13
+ ## Specific to RubyMotion:
14
+ .dat*
15
+ .repl_history
16
+ build/
17
+
18
+ ## Documentation cache and generated files:
19
+ /.yardoc/
20
+ /_yardoc/
21
+ /doc/
22
+ /rdoc/
23
+
24
+ ## Environment normalisation:
25
+ /.bundle/
26
+ /vendor/bundle
27
+ /lib/bundler/man/
28
+
29
+ # for a library or gem, you might want to ignore these files since the code is
30
+ # intended to run in multiple environments; otherwise, check them in:
31
+ Gemfile.lock
32
+ # .ruby-version
33
+ # .ruby-gemset
34
+
35
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
36
+ .rvmrc
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1 @@
1
+ ttt
@@ -0,0 +1 @@
1
+ 2.2.1
@@ -0,0 +1,2 @@
1
+ language: ruby
2
+
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+ gem 'pry'
3
+ gem 'pry-byebug'
4
+
5
+ group :test do
6
+ gem 'rake'
7
+ gem 'simplecov'
8
+ gem 'coveralls', :require => false
9
+ gem 'rspec', :require => 'spec'
10
+ end
@@ -0,0 +1,21 @@
1
+ # Apprenticeship-RubyTicTacToe
2
+
3
+ Tic Tac Toe game implemented in Ruby
4
+
5
+ [![Master Build Status](https://travis-ci.org/gemcfadyen/Apprenticeship-RubyTicTacToe.svg?branch=master)](https://travis-ci.org/gemcfadyen/Apprenticeship-RubyTicTacToe) [![Master Coverage Status](https://coveralls.io/repos/gemcfadyen/Apprenticeship-RubyTicTacToe/badge.svg?branch=master&service=github)](https://coveralls.io/github/gemcfadyen/Apprenticeship-RubyTicTacToe?branch=master)
6
+
7
+ To run the application clone the project into a folder
8
+
9
+ >> git clone git@github.com:gemcfadyen/Apprenticeship-RubyTicTacToe.git
10
+
11
+
12
+ From this folder run the command
13
+
14
+ >> bin/run.sh
15
+
16
+ The game will then start. To make a move, enter a number via the commandline when prompted. If the move is not valid, you will be reprompted until a valid move is given.
17
+
18
+ Once the game is over, the winner will be announced, or the game will be a draw.
19
+
20
+ You can replay by entering Y or y when prompted.
21
+
@@ -0,0 +1,7 @@
1
+ begin
2
+ require 'rspec/core/rake_task'
3
+ RSpec::Core::RakeTask.new(:spec)
4
+ rescue LoadError
5
+ end
6
+
7
+ task :default => :spec
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ##Setup Load Path
4
+ $LOAD_PATH << File.expand_path("../../lib", __FILE__)
5
+
6
+ require 'command_line_app'
7
+ require 'command_line_ui'
8
+ require 'board_factory'
9
+ require 'command_line_player_factory'
10
+ require 'prompt_writer'
11
+ require 'prompt_reader'
12
+
13
+ writer = PromptWriter.new($stdout)
14
+ reader = PromptReader.new($stdin)
15
+ command_line_ui = CommandLineUI.new(writer, reader)
16
+
17
+ board_factory = BoardFactory.new
18
+ player_factory = CommandLinePlayerFactory.new
19
+
20
+ command_line_app = CommandLineApp.new(command_line_ui, board_factory, player_factory)
21
+ command_line_app.start