tic_tac_toe_nhu 0.0.2

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 (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +8 -0
  5. data/Gemfile.lock +39 -0
  6. data/README.md +19 -0
  7. data/Rakefile +15 -0
  8. data/bin/tic_tac_toe +6 -0
  9. data/coverage/.last_run.json +5 -0
  10. data/coverage/.resultset.json +502 -0
  11. data/features/step_definitions/tictactoe_steps.rb +6 -0
  12. data/features/support/env.rb +2 -0
  13. data/features/tictactoe_start_game.feature +11 -0
  14. data/features/tictactoe_submit_move.feature +9 -0
  15. data/lib/tic_tac_toe/board.rb +99 -0
  16. data/lib/tic_tac_toe/game.rb +41 -0
  17. data/lib/tic_tac_toe/game_factory.rb +55 -0
  18. data/lib/tic_tac_toe/main.rb +47 -0
  19. data/lib/tic_tac_toe/player.rb +15 -0
  20. data/lib/tic_tac_toe/player_factory.rb +17 -0
  21. data/lib/tic_tac_toe/rules.rb +32 -0
  22. data/lib/tic_tac_toe/strategy/console_user.rb +26 -0
  23. data/lib/tic_tac_toe/strategy/minimax.rb +83 -0
  24. data/lib/tic_tac_toe/ui/console.rb +60 -0
  25. data/spec/integration/tictactoe/tic_tac_toe.rb +7 -0
  26. data/spec/mocks/game.rb +11 -0
  27. data/spec/mocks/game_factory.rb +8 -0
  28. data/spec/mocks/player_factory.rb +8 -0
  29. data/spec/mocks/rules.rb +9 -0
  30. data/spec/mocks/strategy/dynamic.rb +19 -0
  31. data/spec/mocks/ui/console.rb +15 -0
  32. data/spec/tic_tac_toe/board_spec.rb +186 -0
  33. data/spec/tic_tac_toe/game_factory_spec.rb +78 -0
  34. data/spec/tic_tac_toe/game_spec.rb +94 -0
  35. data/spec/tic_tac_toe/main_spec.rb +104 -0
  36. data/spec/tic_tac_toe/player_factory_mock.rb +10 -0
  37. data/spec/tic_tac_toe/player_factory_spec.rb +59 -0
  38. data/spec/tic_tac_toe/player_spec.rb +32 -0
  39. data/spec/tic_tac_toe/rules_spec.rb +185 -0
  40. data/spec/tic_tac_toe/spec_helper.rb +9 -0
  41. data/spec/tic_tac_toe/strategy/console_user_spec.rb +34 -0
  42. data/spec/tic_tac_toe/strategy/minimax_spec.rb +163 -0
  43. data/spec/tic_tac_toe/strategy/mock.rb +19 -0
  44. data/spec/tic_tac_toe/ui/console_spec.rb +93 -0
  45. data/tic_tac_toe_nhu.gemspec +11 -0
  46. metadata +86 -0
@@ -0,0 +1,185 @@
1
+ require 'tic_tac_toe/spec_helper'
2
+ require 'tic_tac_toe/rules'
3
+ require 'tic_tac_toe/board'
4
+
5
+ describe TicTacToe::Rules do
6
+
7
+ before(:each) do
8
+ @player = "X"
9
+ @opponent = "O"
10
+ @board = TicTacToe::Board.new(3)
11
+ @rules = TicTacToe::Rules.new(@board)
12
+ end
13
+
14
+ context "game is not over" do
15
+ it "when no one made a move" do
16
+ @rules.should_not be_game_over
17
+ end
18
+
19
+ it "when there is only one marked square" do
20
+ mark([0], @player)
21
+ @rules.should_not be_game_over
22
+ end
23
+
24
+ it "when there is no winner and there is one square left" do
25
+ (1...@board.size**2).each {|i| @board.mark(i, i)}
26
+ @rules.should_not be_game_over
27
+ end
28
+ end
29
+
30
+ context "tie" do
31
+ it "is not a tied when there is no mark on the board" do
32
+ @rules.should_not be_tied
33
+ end
34
+
35
+ it "is not a tied when there is a winner" do
36
+ mark([0, 1, 2], @player)
37
+ @rules.should_not be_tied
38
+ end
39
+
40
+ it "is not tied when there is a winner and the board is filled" do
41
+ mark([0, 2, 4, 6, 8], @player)
42
+ mark([1, 3, 5, 7], @opponent)
43
+ @rules.should_not be_tied
44
+ end
45
+
46
+ it "is tied when there is no winner and the board is filled" do
47
+ mark([0, 2, 3, 4, 7], @player)
48
+ mark([1, 5, 6, 8], @opponent)
49
+ @rules.should be_tied
50
+ end
51
+ end
52
+
53
+ context "game over when there is a winner" do
54
+ it "when player wins horizontally" do
55
+ mark([0, 1, 2], @player)
56
+ @rules.should be_game_over
57
+ end
58
+
59
+ it "when player wins vertially" do
60
+ mark([1, 4, 7], @player)
61
+ @rules.should be_game_over
62
+ end
63
+
64
+ it "when player wins diagonally" do
65
+ mark([2, 4, 6], @player)
66
+ @rules.should be_game_over
67
+ end
68
+
69
+ it "when opponent wins" do
70
+ mark([0, 4, 8], @opponent)
71
+ @rules.should be_game_over
72
+ end
73
+ end
74
+
75
+ it "game over when there is a tie" do
76
+ mark((0...@board.size**2).to_a, "i")
77
+ @rules.should be_game_over
78
+ end
79
+
80
+
81
+ context "winner" do
82
+ context "wins horizontally" do
83
+ it "is the player when player marks all the first row" do
84
+ mark([0, 1, 2], @player)
85
+ @rules.winner.should == @player
86
+ end
87
+
88
+ it "is the player when player marks all the middle row" do
89
+ mark([3, 4, 5], @player)
90
+ @rules.winner.should == @player
91
+ end
92
+
93
+ it "is the player when player marks all the last row" do
94
+ mark([6, 7, 8], @player)
95
+ @rules.winner.should == @player
96
+ end
97
+
98
+ it "is the opponent when opponent marks all the middle row" do
99
+ mark([3, 4, 5], @opponent)
100
+ @rules.winner.should == @opponent
101
+ end
102
+
103
+ it "is nil when player marks two horizontal squares" do
104
+ mark([0, 1], @player)
105
+ @rules.winner.should be_nil
106
+ end
107
+
108
+ it "is nil when player marks two squares and opponent marks one" do
109
+ mark([0, 2], @player)
110
+ mark([1], @opponent)
111
+ @rules.winner.should be_nil
112
+ end
113
+ end
114
+
115
+ context "wins vertically" do
116
+ it "is the opponent when opponent marks all the first column" do
117
+ mark([0, 3, 6], @opponent)
118
+ @rules.winner.should == @opponent
119
+ end
120
+
121
+ it "is the opponent when opponent marks all the middle column" do
122
+ mark([1, 4, 7], @opponent)
123
+ @rules.winner.should == @opponent
124
+ end
125
+
126
+ it "is the opponent when opponent marks the last column" do
127
+ mark([2, 5, 8], @opponent)
128
+ @rules.winner.should == @opponent
129
+ end
130
+
131
+ it "is the player when player marks all the middle column" do
132
+ mark([1, 4, 7], @player)
133
+ @rules.winner.should == @player
134
+ end
135
+
136
+ it "is nil when player marks two vertical squares" do
137
+ mark([2, 5], @player)
138
+ @rules.winner.should be_nil
139
+ end
140
+
141
+ it "is nil when player marks two squares and opponent marks one" do
142
+ mark([0, 3], @player)
143
+ mark([6], @opponent)
144
+ @rules.winner.should be_nil
145
+ end
146
+ end
147
+
148
+ context "wins diagonally" do
149
+ it "is player when player marks all the top left to right diagonal squares" do
150
+ mark([0, 4, 8], @player)
151
+ @rules.winner.should == @player
152
+ end
153
+
154
+ it "is opponent when opponent marks all the top right to left diagonal squares" do
155
+ mark([2, 4, 6], @opponent)
156
+ @rules.winner.should == @opponent
157
+ end
158
+
159
+ it "is nil when player marks only two top left to right diagonal squares" do
160
+ mark([0, 4], @player)
161
+ @rules.winner.should be_nil
162
+ end
163
+
164
+ it "is nil when player marks only two top right to left diagonal squares" do
165
+ mark([2, 4], @player)
166
+ @rules.winner.should be_nil
167
+ end
168
+
169
+ it "is nil when player marks two squares and opponent marks one" do
170
+ mark([0, 4], @player)
171
+ mark([8], @opponent)
172
+ @rules.winner.should be_nil
173
+ end
174
+ end
175
+
176
+ it "is nil when there is a tied" do
177
+ (@board.size**2).times {|i| @board.mark(i, i)}
178
+ @rules.winner.should be_nil
179
+ end
180
+ end
181
+
182
+ def mark(squares, value)
183
+ squares.each {|i| @board.mark(i, value)}
184
+ end
185
+ end
@@ -0,0 +1,9 @@
1
+ begin
2
+ require 'simplecov'
3
+ SimpleCov.start do
4
+ add_filter "/spec/"
5
+ end
6
+
7
+ rescue LoadError
8
+ puts 'Coverage disabled, enable by installing simplecov'
9
+ end
@@ -0,0 +1,34 @@
1
+ require 'tic_tac_toe/spec_helper'
2
+ require 'tic_tac_toe/strategy/console_user'
3
+
4
+ describe TicTacToe::Strategy::ConsoleUser do
5
+
6
+ context "gets move" do
7
+ before(:each) do
8
+ @input = StringIO.new
9
+ @output = StringIO.new
10
+ @strategy = TicTacToe::Strategy::ConsoleUser.new(@input, @output)
11
+ end
12
+
13
+ it "prompts the user for a move" do
14
+ @output.should_receive(:puts).with("Please enter a square number that is not marked: ")
15
+ @input.should_receive(:gets).and_return("3")
16
+ @strategy.move
17
+ end
18
+
19
+ it "returns a number when user enters a number" do
20
+ move = "2"
21
+ @input.should_receive(:gets).and_return(move)
22
+ @strategy.move.should == move.to_i
23
+ end
24
+
25
+ it "asks for user input again when user enter a character" do
26
+ invalid_move = "a"
27
+ valid_move = "2"
28
+ @input.should_receive(:gets).and_return(invalid_move, invalid_move, valid_move)
29
+ @output.should_receive(:puts).with("Please enter a square number that is not marked: ").at_least(2).times
30
+ @strategy.move.should == valid_move.to_i
31
+ end
32
+ end
33
+
34
+ end
@@ -0,0 +1,163 @@
1
+ require 'tic_tac_toe/spec_helper'
2
+ require 'tic_tac_toe/board'
3
+ require 'tic_tac_toe/strategy/minimax'
4
+
5
+ describe TicTacToe::Strategy::Minimax, :slow_test => true do
6
+
7
+ before(:each) do
8
+ @board = TicTacToe::Board.new(3)
9
+ @opponent = "X"
10
+ @computer = "O"
11
+ @strategy = TicTacToe::Strategy::Minimax.new(@board, @computer, @opponent)
12
+ end
13
+
14
+ context "move" do
15
+ context "when there is only one position left" do
16
+ it "returns move when it's a winning move" do
17
+ mark((1...@board.size**2), @computer)
18
+ @strategy.move.should == 0
19
+ end
20
+
21
+ it "returns the move when it's a tied" do
22
+ mark([0, 2, 5, 6], @computer)
23
+ mark([1, 3, 4, 8], @opponent)
24
+ @strategy.move.should == 7
25
+ end
26
+
27
+ it "returns the move when opponent wins" do
28
+ mark((0...@board.size**2 - 1).to_a, @opponent)
29
+ @strategy.move.should == 8
30
+ end
31
+ end
32
+
33
+ context "when there are two positions left" do
34
+ it "returns losing scores when the two moves are losing moves" do
35
+ mark((2...@board.size**2).to_a, @opponent)
36
+ @strategy.move.should == 0
37
+ end
38
+
39
+ it "returns the first win move when the two moves are winning moves" do
40
+ mark((2...@board.size**2).to_a, @computer)
41
+ @strategy.move.should == 0
42
+ end
43
+
44
+ it "returns the first tie move when the two moves are tie moves" do
45
+ mark([0, 2, 7], @computer)
46
+ mark([1, 4, 6, 8], @opponent)
47
+ @strategy.move.should == 3
48
+ end
49
+
50
+ it "returns win move when there are winning and losing moves" do
51
+ mark([0, 1, 3, 7], @computer)
52
+ mark([2, 4, 5], @opponent)
53
+ @strategy.move.should == 6
54
+ end
55
+
56
+ it "returns winning move when there are winning and tie moves" do
57
+ mark([0, 2, 3, 4], @computer)
58
+ mark([1, 5, 8], @opponent)
59
+ @strategy.move.should == 6
60
+ end
61
+
62
+ it "returns tied move when there are losing and tie moves" do
63
+ mark([2, 3, 4], @computer)
64
+ mark([0, 5, 6, 7], @opponent)
65
+ @strategy.move.should == 8
66
+ end
67
+
68
+ context "winning move appear later in the board" do
69
+ it "returns win move when winning move is later than losing move" do
70
+ mark([1, 2, 5, 7], @computer)
71
+ mark([0, 3, 4], @opponent)
72
+ @strategy.move.should == 8
73
+ end
74
+
75
+ it "returns winning move when winning move is later than tie move" do
76
+ mark([0, 2, 4, 5], @computer)
77
+ mark([1, 3, 6], @opponent)
78
+ @strategy.move.should == 8
79
+ end
80
+
81
+ it "returns tied move when there are losing and tie moves" do
82
+ mark([2, 3, 4], @computer)
83
+ mark([0, 5, 6, 7], @opponent)
84
+ @strategy.move.should == 8
85
+ end
86
+ end
87
+ end
88
+
89
+ context "when there are three moves left" do
90
+ it "chooses the winning move when there is one available" do
91
+ mark([1, 4], @computer)
92
+ mark([0, 3, 2, 5], @opponent)
93
+ @strategy.move.should == 7
94
+ end
95
+
96
+ it "chooses a tie move when there are only losing and tie moves" do
97
+ mark([1, 4], @computer)
98
+ mark([0, 2, 5, 7], @opponent)
99
+ @strategy.move.should == 8
100
+ end
101
+ end
102
+
103
+ context "when there are 4 moves left" do
104
+ it "chooses a winning move when one is available" do
105
+ mark([0, 4], @computer)
106
+ mark([1, 2, 6], @opponent)
107
+ @strategy.move.should == 8
108
+ end
109
+
110
+ it "chooses a move that would create 2 winning moves" do
111
+ mark([0, 6], @computer)
112
+ mark([1, 3, 5], @opponent)
113
+ @strategy.move.should == 4
114
+ end
115
+ end
116
+ end
117
+
118
+ it "chooses the winning move when available" do
119
+ mark([1, 4], @computer)
120
+ mark([0], @opponent)
121
+ @strategy.move.should == 7
122
+ end
123
+
124
+ it "chooses the winning move when available" do
125
+ mark([0, 4], @computer)
126
+ mark([1, 2], @opponent)
127
+ @strategy.move.should == 8
128
+ end
129
+
130
+ it "chooses a blocking move when there is no winning move" do
131
+ mark([2], @computer)
132
+ mark([0, 4], @opponent)
133
+ @strategy.move.should == 8
134
+ end
135
+
136
+ it "chooses a blocking move when there is no winning move" do
137
+ mark([2], @computer)
138
+ mark([1, 4], @opponent)
139
+ @strategy.move.should == 7
140
+ end
141
+
142
+ it "chooses the middle square when computer is the second player" do
143
+ mark([0], @opponent)
144
+ @strategy.move.should == 4
145
+ end
146
+
147
+ it "chooses the first corner of the board when the middle square is taken as a second player" do
148
+ mark([4], @opponent)
149
+ @strategy.move.should == 0
150
+ end
151
+
152
+ it "chooses the middle square on the first move" do
153
+ @strategy.move.should == 4
154
+ end
155
+
156
+ def move_node(move, score)
157
+ TicTacToe::Move.new(move, score)
158
+ end
159
+
160
+ def mark(squares, value)
161
+ squares.each {|i| @board.mark(i, value)}
162
+ end
163
+ end
@@ -0,0 +1,19 @@
1
+ class MockStrategy
2
+ attr_accessor :moves
3
+
4
+ def initialize(moves = [])
5
+ @moves = moves
6
+ end
7
+
8
+ def add_move(move)
9
+ @moves << move
10
+ end
11
+
12
+ def move
13
+ @moves.shift
14
+ end
15
+
16
+ def needs_input?
17
+ true
18
+ end
19
+ end
@@ -0,0 +1,93 @@
1
+ require 'tic_tac_toe/spec_helper'
2
+ require 'tic_tac_toe/ui/console'
3
+ require 'tic_tac_toe/board'
4
+ require 'tic_tac_toe/player'
5
+
6
+ describe TicTacToe::Console do
7
+
8
+ before(:each) do
9
+ @size = 2
10
+ @output = StringIO.new
11
+ @input = StringIO.new
12
+ @board = TicTacToe::Board.new(2)
13
+ @console = TicTacToe::Console.new(@input, @output)
14
+ end
15
+
16
+ it "displays welcome message" do
17
+ @output.should_receive(:puts).with("Welcome to Tic Tac Toe!")
18
+ @console.display_welcome_message
19
+ end
20
+
21
+ context "displays the board" do
22
+ it "shows numbers for all unmarked squares" do
23
+ expected_display = "| 0 | 1 |\n| 2 | 3 |\n"
24
+ @output.should_receive(:puts).with(expected_display)
25
+ @console.display_board(@board)
26
+ end
27
+
28
+ it "shows the player value on the marked square" do
29
+ @board.mark(0, "X")
30
+ expected_display = "| X | 1 |\n| 2 | 3 |\n"
31
+ @output.should_receive(:puts).with(expected_display)
32
+ @console.display_board(@board)
33
+ end
34
+
35
+ it "shows the player values when all the squares are marked" do
36
+ (0...@size**2).each {|value| @board.mark(value, "O")}
37
+ expected_display = "| O | O |\n| O | O |\n"
38
+ @output.should_receive(:puts).with(expected_display)
39
+ @console.display_board(@board)
40
+ end
41
+
42
+ it "displays a 3x3 board" do
43
+ @board = TicTacToe::Board.new(3)
44
+ @console = TicTacToe::Console.new(@input, @output)
45
+ expected_display = "| 0 | 1 | 2 |\n| 3 | 4 | 5 |\n| 6 | 7 | 8 |\n"
46
+ @output.should_receive(:puts).with(expected_display)
47
+ @console.display_board(@board)
48
+ end
49
+ end
50
+
51
+ context "reading user input for game type" do
52
+ it "displays a list of game type" do
53
+ expected_display = "1 - You vs Computer\n2 - Computer vs You\n3 - You vs Friend"
54
+ @input.string = "1"
55
+ @console.game_type
56
+ @output.string.should match expected_display
57
+ end
58
+
59
+ it "displays a message asking user to select a game type" do
60
+ expected_display = "Please select a game type."
61
+ @input.string = "1"
62
+ @console.game_type
63
+ @output.string.should match expected_display
64
+ end
65
+
66
+ it "returns user input in integer" do
67
+ @input.string = "1"
68
+ @console.game_type.should == 1
69
+ end
70
+ end
71
+
72
+ it "displays winner" do
73
+ player = TicTacToe::Player.new("Todd", "X", nil)
74
+ @console.display_winner(player)
75
+ @output.string.should == "Todd(X) win!\n"
76
+ end
77
+
78
+ it "display tied game" do
79
+ @console.display_tied_game
80
+ @output.string.should == "It's a tied!\n"
81
+ end
82
+
83
+ it "displays square is not available" do
84
+ @console.display_square_not_available
85
+ @output.string.should match "Square is not available. Please enter a different square."
86
+ end
87
+
88
+ it "displays player turns" do
89
+ player = TicTacToe::Player.new("Todd", "X", nil)
90
+ @console.display_player_turn(player)
91
+ @output.string.should == "It's Todd(X) turn.\n"
92
+ end
93
+ end
@@ -0,0 +1,11 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'tic_tac_toe_nhu'
3
+ s.version = '0.0.2'
4
+ s.date = '2013-06-11'
5
+ s.summary = "Tic Tac Toe"
6
+ s.description = "A simple tic tac toe game with AI"
7
+ s.authors = ["Nhu Nguyen"]
8
+ s.email = 'nhu313@gmail.com'
9
+ s.files = `git ls-files`.split("\n")
10
+ s.homepage = 'http://rubygems.org/gems/tic_tac_toe_nhu'
11
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tic_tac_toe_nhu
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Nhu Nguyen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-06-11 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A simple tic tac toe game with AI
14
+ email: nhu313@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - .gitignore
20
+ - .ruby-version
21
+ - Gemfile
22
+ - Gemfile.lock
23
+ - README.md
24
+ - Rakefile
25
+ - bin/tic_tac_toe
26
+ - coverage/.last_run.json
27
+ - coverage/.resultset.json
28
+ - features/step_definitions/tictactoe_steps.rb
29
+ - features/support/env.rb
30
+ - features/tictactoe_start_game.feature
31
+ - features/tictactoe_submit_move.feature
32
+ - lib/tic_tac_toe/board.rb
33
+ - lib/tic_tac_toe/game.rb
34
+ - lib/tic_tac_toe/game_factory.rb
35
+ - lib/tic_tac_toe/main.rb
36
+ - lib/tic_tac_toe/player.rb
37
+ - lib/tic_tac_toe/player_factory.rb
38
+ - lib/tic_tac_toe/rules.rb
39
+ - lib/tic_tac_toe/strategy/console_user.rb
40
+ - lib/tic_tac_toe/strategy/minimax.rb
41
+ - lib/tic_tac_toe/ui/console.rb
42
+ - spec/integration/tictactoe/tic_tac_toe.rb
43
+ - spec/mocks/game.rb
44
+ - spec/mocks/game_factory.rb
45
+ - spec/mocks/player_factory.rb
46
+ - spec/mocks/rules.rb
47
+ - spec/mocks/strategy/dynamic.rb
48
+ - spec/mocks/ui/console.rb
49
+ - spec/tic_tac_toe/board_spec.rb
50
+ - spec/tic_tac_toe/game_factory_spec.rb
51
+ - spec/tic_tac_toe/game_spec.rb
52
+ - spec/tic_tac_toe/main_spec.rb
53
+ - spec/tic_tac_toe/player_factory_mock.rb
54
+ - spec/tic_tac_toe/player_factory_spec.rb
55
+ - spec/tic_tac_toe/player_spec.rb
56
+ - spec/tic_tac_toe/rules_spec.rb
57
+ - spec/tic_tac_toe/spec_helper.rb
58
+ - spec/tic_tac_toe/strategy/console_user_spec.rb
59
+ - spec/tic_tac_toe/strategy/minimax_spec.rb
60
+ - spec/tic_tac_toe/strategy/mock.rb
61
+ - spec/tic_tac_toe/ui/console_spec.rb
62
+ - tic_tac_toe_nhu.gemspec
63
+ homepage: http://rubygems.org/gems/tic_tac_toe_nhu
64
+ licenses: []
65
+ metadata: {}
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 2.0.3
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: Tic Tac Toe
86
+ test_files: []