ttt 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +6 -0
- data/Gemfile.lock +51 -0
- data/MIT-License.md +8 -0
- data/Rakefile +324 -0
- data/Readme.md +35 -0
- data/bin/ttt +6 -0
- data/features/binary.feature +39 -0
- data/features/computer_player.feature +62 -0
- data/features/create_game.feature +63 -0
- data/features/finish_game.feature +53 -0
- data/features/finished_states.feature +56 -0
- data/features/mark_board.feature +24 -0
- data/features/step_definitions/binary_steps.rb +42 -0
- data/features/step_definitions/ttt_steps.rb +82 -0
- data/features/support/env.rb +8 -0
- data/features/view_board_as_developer.feature +13 -0
- data/features/view_board_as_tester.feature +9 -0
- data/lib/ttt.rb +1 -0
- data/lib/ttt/binary.rb +96 -0
- data/lib/ttt/computer_player.rb +74 -0
- data/lib/ttt/game.rb +129 -0
- data/lib/ttt/interface.rb +22 -0
- data/lib/ttt/interface/cli.rb +95 -0
- data/lib/ttt/interface/cli/players.rb +56 -0
- data/lib/ttt/interface/cli/views.rb +124 -0
- data/lib/ttt/interface/limelight.rb +18 -0
- data/lib/ttt/interface/limelight/players/restart_as_first.rb +5 -0
- data/lib/ttt/interface/limelight/players/restart_as_second.rb +6 -0
- data/lib/ttt/interface/limelight/players/square.rb +105 -0
- data/lib/ttt/interface/limelight/props.rb +10 -0
- data/lib/ttt/interface/limelight/styles.rb +101 -0
- data/lib/ttt/ratings.rb +849 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/ttt/computer_player_spec.rb +86 -0
- data/spec/ttt/game_spec.rb +294 -0
- data/spec/ttt/rating_spec.rb +75 -0
- metadata +139 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
builder (3.0.0)
|
5
|
+
bundler-bouncer (0.1.2)
|
6
|
+
coderay (0.9.8)
|
7
|
+
cucumber (1.0.2)
|
8
|
+
builder (>= 2.1.2)
|
9
|
+
diff-lcs (>= 1.1.2)
|
10
|
+
gherkin (~> 2.4.5)
|
11
|
+
json (>= 1.4.6)
|
12
|
+
term-ansicolor (>= 1.0.5)
|
13
|
+
diff-lcs (1.1.2)
|
14
|
+
gherkin (2.4.5)
|
15
|
+
json (>= 1.4.6)
|
16
|
+
gherkin (2.4.5-java)
|
17
|
+
json (>= 1.4.6)
|
18
|
+
json (1.5.3)
|
19
|
+
json (1.5.3-java)
|
20
|
+
method_source (0.6.0)
|
21
|
+
ruby_parser (>= 2.0.5)
|
22
|
+
pry (0.9.3)
|
23
|
+
coderay (>= 0.9.8)
|
24
|
+
method_source (>= 0.6.0)
|
25
|
+
ruby_parser (>= 2.0.5)
|
26
|
+
slop (~> 1.9.0)
|
27
|
+
rake (0.9.2)
|
28
|
+
rspec (2.6.0)
|
29
|
+
rspec-core (~> 2.6.0)
|
30
|
+
rspec-expectations (~> 2.6.0)
|
31
|
+
rspec-mocks (~> 2.6.0)
|
32
|
+
rspec-core (2.6.4)
|
33
|
+
rspec-expectations (2.6.0)
|
34
|
+
diff-lcs (~> 1.1.2)
|
35
|
+
rspec-mocks (2.6.0)
|
36
|
+
ruby_parser (2.0.6)
|
37
|
+
sexp_processor (~> 3.0)
|
38
|
+
sexp_processor (3.0.5)
|
39
|
+
slop (1.9.1)
|
40
|
+
term-ansicolor (1.0.6)
|
41
|
+
|
42
|
+
PLATFORMS
|
43
|
+
java
|
44
|
+
ruby
|
45
|
+
|
46
|
+
DEPENDENCIES
|
47
|
+
bundler-bouncer (~> 0.1.2)
|
48
|
+
cucumber (~> 1.0.2)
|
49
|
+
pry (~> 0.9.3)
|
50
|
+
rake (~> 0.9.2)
|
51
|
+
rspec (~> 2.6.0)
|
data/MIT-License.md
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
Copyright (c) 2011 Joshua Cheek
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
8
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,324 @@
|
|
1
|
+
require 'bundler/bouncer'
|
2
|
+
|
3
|
+
# load the lib
|
4
|
+
task :environment do
|
5
|
+
$:.unshift File.expand_path('../lib', __FILE__)
|
6
|
+
require 'ttt'
|
7
|
+
require 'ttt/computer_player'
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
# commonly invoked interfaces
|
13
|
+
desc 'Open a pry console with the app loaded'
|
14
|
+
task :console do
|
15
|
+
sh 'pry -I lib -r ttt -r ttt/computer_player'
|
16
|
+
end
|
17
|
+
|
18
|
+
desc 'Run Cucumber against the features'
|
19
|
+
task :cuke do
|
20
|
+
sh 'cucumber'
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'run RSpec against the specification'
|
24
|
+
task :spec do
|
25
|
+
sh 'rspec spec --colour'
|
26
|
+
end
|
27
|
+
task :rspec => :spec # synonym
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
# handle gem construction
|
32
|
+
require "rubygems/package_task"
|
33
|
+
spec = Gem::Specification.new do |s|
|
34
|
+
# informatoin
|
35
|
+
s.name = "ttt"
|
36
|
+
s.version = "1.0.0"
|
37
|
+
s.summary = "Tic Tac Toe lib + binary"
|
38
|
+
s.description = "TTT is a Tic Tac Toe lib, as well as a CLI and GUI to play it."
|
39
|
+
s.author = "Joshua J Cheek"
|
40
|
+
s.email = "josh.cheek@gmail.com"
|
41
|
+
s.homepage = "https://github.com/JoshCheek/ttt"
|
42
|
+
|
43
|
+
# additional files
|
44
|
+
s.files = %w(Gemfile Gemfile.lock MIT-License.md Rakefile Readme.md) + Dir.glob("{bin,spec,features,lib}/**/*")
|
45
|
+
s.executables = FileList["bin/**"].map { |f| File.basename(f) }
|
46
|
+
s.require_paths = ["lib"]
|
47
|
+
|
48
|
+
# dependencies
|
49
|
+
s.add_development_dependency "bundler-bouncer" , "~> 0.1.2"
|
50
|
+
s.add_development_dependency "rspec" , "~> 2.6.0"
|
51
|
+
s.add_development_dependency "cucumber" , "~> 1.0.2"
|
52
|
+
s.add_development_dependency "pry" , "~> 0.9.3"
|
53
|
+
s.add_development_dependency "rake" , "~> 0.9.2"
|
54
|
+
end
|
55
|
+
|
56
|
+
task :package => :gemspec
|
57
|
+
Gem::PackageTask.new(spec) do |pkg|
|
58
|
+
pkg.gem_spec = spec
|
59
|
+
end
|
60
|
+
|
61
|
+
desc "Build the gemspec file #{spec.name}.gemspec"
|
62
|
+
task :gemspec do
|
63
|
+
file = File.dirname(__FILE__) + "/#{spec.name}.gemspec"
|
64
|
+
File.open(file, "w") {|f| f << spec.to_ruby }
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
# Various command line utilities constructed while building the gem
|
72
|
+
namespace :script do
|
73
|
+
|
74
|
+
# cache the boards b/c computing them takes a long time
|
75
|
+
# these were generated with the compute_congruent task below
|
76
|
+
def self.all_boards_cached
|
77
|
+
%w[
|
78
|
+
000000000 100000000 120000000 121000000 121200000 121210000 121212000 121212100 121212010 121212210
|
79
|
+
121212211 121210200 121211200 121211220 121211221 121211202 121211212 121210210 121210212 121210201
|
80
|
+
121210020 121211020 121211022 121210021 121210002 121211002 121210102 121210012 121201000 121221000
|
81
|
+
121221100 121221120 121221102 121221112 121221010 121221210 121221211 121221012 121221001 121201200
|
82
|
+
121201210 121201212 121201201 121201020 121201120 121201122 121201021 121201002 121201102 121201012
|
83
|
+
121200100 121220100 121220101 121222101 121202100 121202101 121202121 121212121 121200102 121200010
|
84
|
+
121220010 121220011 121220211 121202010 121200210 121200211 121200012 121200001 121220001 121200201
|
85
|
+
121200021 121020000 121120000 121120200 121121200 121121220 121121202 121121212 121120210 121120212
|
86
|
+
121120201 121120221 121120020 121120002 121120102 121120012 121020100 121020120 121020102 121020112
|
87
|
+
121020010 121020210 121000200 121100200 121100220 121110220 121110222 121101220 121101222 121100221
|
88
|
+
121100202 121110202 121101202 121100212 121010200 121010220 121011220 121010221 121010202 121010212
|
89
|
+
121001200 121001220 121001221 121000210 121000212 121000201 121000221 121000020 121100020 121010020
|
90
|
+
121000120 120100000 122100000 122110000 122112000 122112100 122112010 122112210 122112211 122112012
|
91
|
+
122112001 122110200 122111200 122110210 122110212 122111212 122110201 122110020 122111020 122110120
|
92
|
+
122110021 122110002 122111002 122110102 122110012 122101000 122121000 122121100 122121010 122121210
|
93
|
+
122121012 122121112 122121001 122121201 122121021 122101200 122101210 122101212 122101201 122101221
|
94
|
+
122111221 122101020 122101120 122101021 122101002 122101102 122101012 122100100 122100010 122120010
|
95
|
+
122120110 122120011 122122011 122122111 122120211 122102010 122102110 122102011 122102211 122100210
|
96
|
+
122100211 122100012 122100112 122100001 122120001 122120101 122102001 122102101 122100201 122100021
|
97
|
+
120120000 120121000 120121200 120121210 120121212 120121201 120121020 120121002 120121102 120121012
|
98
|
+
120120100 120120010 120122010 120122110 120122011 120122211 120120210 120120211 120120012 120120112
|
99
|
+
120120001 120122001 120122101 120120201 120120021 120102000 120112000 120112200 120112210 120112212
|
100
|
+
120112201 120112020 120112120 120112021 120112002 120112102 120112012 120102100 120102010 120102210
|
101
|
+
120102211 120102012 120102112 120102001 120102201 120102021 120100200 120110200 120110220 120111220
|
102
|
+
120110221 120110202 120111202 120110212 120101200 120101220 120101202 120101212 120100210 120100212
|
103
|
+
120100201 120100221 120100020 120110020 120110022 120111022 120101020 120101022 120100120 120100021
|
104
|
+
120100002 120110002 120101002 120100102 120100012 120010000 122010000 122011000 122211000 122211010
|
105
|
+
122211210 122211211 122211012 122211001 122011200 122011210 122011212 122011201 122011020 122011120
|
106
|
+
122011122 122111122 122011002 122011102 122011012 122010100 122012100 122012110 122012112 122012101
|
107
|
+
122010120 122010102 122010112 122010010 122210010 122210011 122012010 122010210 122010211 122010012
|
108
|
+
122010001 120210000 120211000 120211020 120211002 120211012 120210001 120012000 120012100 120012120
|
109
|
+
120012102 120012112 120012010 120012210 120012012 120012001 120010200 120011200 120011220 120011202
|
110
|
+
120011212 120010210 120010212 120010201 120010020 120011020 120011022 120010120 120010021 120010002
|
111
|
+
120011002 120010102 120010012 120001000 122001000 122001100 122021100 122021110 122021112 122021101
|
112
|
+
122001120 122001102 122001112 122001010 122201010 122201011 122221011 122201211 122021010 122021011
|
113
|
+
122021211 122001210 122001211 122001012 122001001 122201001 122021001 122001201 120201000 120201010
|
114
|
+
120221010 120221011 120201012 120201001 120221001 120201201 120021000 120021100 120021120 120021102
|
115
|
+
120021112 120021010 120021210 120021211 120021012 120021001 120021201 120001200 120001210 120001212
|
116
|
+
120001201 120001020 120001120 120001002 120001102 120001012 120000100 122000100 122000110 122020110
|
117
|
+
122020111 122002110 122000112 122000101 122020101 122002101 120020100 120020110 120022110 120020112
|
118
|
+
120020101 120022101 120002100 120002110 120002112 120002101 120000120 120000102 120000112 120000010
|
119
|
+
122000010 122000011 122020011 122000211 120020010 120020011 120020211 120002010 120000210 120000211
|
120
|
+
120000012 120000001 122000001 120200001 120020001 120002001 120000201 120000021 102000000 112000000
|
121
|
+
112020000 112120000 112122000 112122100 112122010 112122210 112122012 112120200 112120020 112121020
|
122
|
+
112121022 112120002 112121002 112121202 112120102 112120012 112021000 112021200 112021020 112021002
|
123
|
+
112021102 112021012 112021212 112020100 112022100 112022110 112022112 112020102 112020112 112020010
|
124
|
+
112022010 112020210 112020012 112020001 112020201 112002000 112102000 112102200 112112200 112112220
|
125
|
+
112112202 112102210 112102212 112102020 112112020 112112022 112102002 112012000 112012200 112012210
|
126
|
+
112012020 112012002 112002100 112002102 112002010 112002210 112002012 112000200 112100200 112100202
|
127
|
+
112110202 112101202 112010200 112010220 112011220 112011222 112010202 112011202 112010212 112001200
|
128
|
+
112001220 112001202 112001212 112000210 112000212 112000201 112000020 112100020 112100022 112110022
|
129
|
+
112101022 112010020 112010022 112011022 112001020 112001022 112000002 112100002 112010002 112001002
|
130
|
+
112000102 112000012 102100000 102120000 102121000 102121020 102121002 102121102 102121012 102120100
|
131
|
+
102120010 102122010 102122110 102120012 102120001 102102000 102112000 102112020 102112002 102102100
|
132
|
+
102102010 102102012 102100020 102110020 102110022 102111022 102101020 102101022 102100002 102110002
|
133
|
+
102101002 102100102 102100012 102010000 102012000 102012100 102012102 102012010 102012210 102012012
|
134
|
+
102010200 102011200 102011202 102011212 102010201 102010020 102011020 102011022 102010002 102011002
|
135
|
+
102010102 102010012 102001000 102021000 102021100 102021102 102021010 102021210 102021012 102001200
|
136
|
+
102001210 102001212 102001020 102001002 102001102 102001012 102000100 102020100 102020110 102022110
|
137
|
+
102020101 102002100 102002110 102000102 102000010 102020010 102002010 102000012 102000001 102020001
|
138
|
+
102000201 100020000 110020000 110022000 110122000 110122020 110122002 110122012 110022100 110022010
|
139
|
+
110022012 110020020 111020020 110021020 110021022 110020002 110120002 110021002 110020012 101020000
|
140
|
+
101020020 100021000 100021020 100021002 100021012 100020001 100002000 110002000 110002020 110102020
|
141
|
+
110102022 110112022 110012020 110012022 110002002 110102002 110012002 110002012 100102000 100102002
|
142
|
+
100112002 100102012 100012000 100012020 100012002 100012012 100002100 100002010 100002012 100000002
|
143
|
+
110000002 100010002 100001002 010000000 210000000 210100000 212100000 212110000 212112000 212112010
|
144
|
+
212110200 212111200 212110020 212111020 212110002 212110012 212101000 212121000 212121010 212121210
|
145
|
+
212101200 212101210 212101212 212111212 212101020 212100010 212120010 212102010 212100012 210120000
|
146
|
+
210121000 210121020 210121002 210102000 210112000 210112020 210112002 210112012 210102010 210102012
|
147
|
+
210100002 210110002 210101002 210010000 212010000 212010010 210210000 210211000 210211200 210211020
|
148
|
+
210211002 210210010 210012000 210012010 210010200 210011200 210011220 210011202 210010210 210010020
|
149
|
+
210011020 210010002 210011002 210010012 210001000 210201000 210201010 210221010 210201210 210021000
|
150
|
+
210021010 210021210 210001200 210001210 210001020 210001002 210000010 212000010 210200010 210020010
|
151
|
+
210002010 210000210 210000012 010200000 010210000 010212000 010212010 010210200 010211200 010211220
|
152
|
+
010210020 010211020 010210002 010201000 010221000 010221010 010201200 010201020 010200010 010220010
|
153
|
+
010202010 010020000 010120000 010120002 010020010 010000200 010010200 010010220 010010202 010001200
|
154
|
+
010000020 010010020 000010000 200010000 020010000
|
155
|
+
]
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
desc 'Lists the congruent boards (from cache)'
|
160
|
+
task :congruent => :environment do
|
161
|
+
all_boards_cached.each { |board| puts board }
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
desc 'Computes all congruent boards (takes a while)'
|
166
|
+
task :compute_congruent => :environment do
|
167
|
+
def self.all_boards(game=TTT::Game.new, boards=[])
|
168
|
+
return if boards.any? { |prev_board| TTT::Game.congruent? prev_board, game.board }
|
169
|
+
boards << game.board
|
170
|
+
game.available_moves.each do |position|
|
171
|
+
next_game = game.pristine_mark position
|
172
|
+
all_boards next_game, boards
|
173
|
+
end
|
174
|
+
boards
|
175
|
+
end
|
176
|
+
all_boards.each { |board| puts board }
|
177
|
+
end
|
178
|
+
|
179
|
+
|
180
|
+
desc 'Show a 9-digit formatted board in tic-tac-toe format'
|
181
|
+
task :show => :environment do
|
182
|
+
raise 'pass argument board=000000000' unless ENV['board']
|
183
|
+
puts TTT::Game.new(ENV['board']).board(:ttt)
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
desc 'An ultra-simple CLI to play the game'
|
188
|
+
task :play => :environment do
|
189
|
+
game = TTT::Game.new ENV['board'] || '000000000'
|
190
|
+
comp = TTT::ComputerPlayer.new(game)
|
191
|
+
until game.over?
|
192
|
+
comp.take_turn
|
193
|
+
puts game.board(:ttt)
|
194
|
+
break if game.over?
|
195
|
+
game.mark $stdin.gets.to_i
|
196
|
+
end
|
197
|
+
puts "The game is over.", (game.tie? ? "No one wins" : "Player #{game.winner} wins.")
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
desc 'Computes some stats that were listed on Wikipedia to ensure numbers are correct'
|
202
|
+
task :stats => :environment do
|
203
|
+
boards = all_boards_cached.select { |board| TTT::Game.new(board).over? } # according to http://en.wikipedia.org/wiki/Tic-tac-toe
|
204
|
+
puts "#{all_boards_cached.size} unique boards (congruent classes)" # no expectation, size is 765
|
205
|
+
puts "#{boards.size} unique end states" # expect 138 (true)
|
206
|
+
puts "#{boards.select { |board| TTT::Game.new(board).winner == 1 }.size} unique ways for player 1 to win" # expect 91 (true)
|
207
|
+
puts "#{boards.select { |board| TTT::Game.new(board).winner == 2 }.size} unique ways for player 2 to win" # expect 44 (true)
|
208
|
+
puts "#{boards.select { |board| TTT::Game.new(board).tie? }.size} unique ways to tie" # expect 3 (true)
|
209
|
+
end
|
210
|
+
|
211
|
+
|
212
|
+
desc 'Computes ratings for each board for each player'
|
213
|
+
task :ratings => :environment do
|
214
|
+
require 'pp'
|
215
|
+
boards = {}
|
216
|
+
all_boards_cached.each do |board|
|
217
|
+
tree = TTT::Rating.new board
|
218
|
+
boards[board] = {
|
219
|
+
1 => tree.rating_for(1),
|
220
|
+
2 => tree.rating_for(2),
|
221
|
+
}
|
222
|
+
end
|
223
|
+
pp boards
|
224
|
+
end
|
225
|
+
|
226
|
+
|
227
|
+
desc 'CLI to explore the game tree'
|
228
|
+
task :explore => :environment do
|
229
|
+
module TTT
|
230
|
+
class Game
|
231
|
+
# overwrite how board(:ttt) displays so that we can get something condensed enough to display
|
232
|
+
# many on the same line (colour allows us to distinguish the boardspace without using any
|
233
|
+
# more characters than are required to display the markings themselves)
|
234
|
+
def board(format=nil)
|
235
|
+
return @board unless format
|
236
|
+
@board.gsub(/[^12]/, ' ').scan(/.../).map { |line| "\e[44m#{line}\e[0m" }.join("\n")
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
module TTT
|
242
|
+
class ExploreTree
|
243
|
+
|
244
|
+
attr_accessor :tree
|
245
|
+
|
246
|
+
def initialize
|
247
|
+
self.tree = TTT::Rating.new
|
248
|
+
end
|
249
|
+
|
250
|
+
def explore!
|
251
|
+
loop do
|
252
|
+
display_adjacent commands, tree
|
253
|
+
print '> '
|
254
|
+
handle_command $stdin.gets
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
def display_adjacent(*displayables)
|
259
|
+
line_sets = []
|
260
|
+
queues = displayables.map { |displayable| displayable.to_s.split "\n" }
|
261
|
+
until queues.all?(&:empty?)
|
262
|
+
line_sets << [] # add a set for current line
|
263
|
+
queues.each { |queue| line_sets.last << queue.shift unless queue.empty? }
|
264
|
+
end
|
265
|
+
puts line_sets.map { |set| set.join ' ' }.join("\n")
|
266
|
+
end
|
267
|
+
|
268
|
+
def commands
|
269
|
+
"------------------\n"\
|
270
|
+
"| COMMANDS |\n"\
|
271
|
+
"|----------------|\n"\
|
272
|
+
"| move position |\n"\
|
273
|
+
"| show [depth] |\n"\
|
274
|
+
"| back |\n"\
|
275
|
+
"| rate player |\n"\
|
276
|
+
"| exit |\n"\
|
277
|
+
"------------------\n"
|
278
|
+
end
|
279
|
+
|
280
|
+
def handle_command(command)
|
281
|
+
args = command.split
|
282
|
+
command = args.shift
|
283
|
+
send command, *args if command
|
284
|
+
rescue => e
|
285
|
+
puts "Invalid command (#{e.message})"
|
286
|
+
end
|
287
|
+
|
288
|
+
def move(n)
|
289
|
+
self.tree = tree.children[n.to_i] || raise("No child at #{n.inspect}")
|
290
|
+
end
|
291
|
+
|
292
|
+
def colour_if_complete(tree)
|
293
|
+
return tree.to_s unless tree.game.over?
|
294
|
+
tree.to_s.split("\n").map { |line| "\e[33;1m#{line}\e[0m" }.join("\n")
|
295
|
+
end
|
296
|
+
|
297
|
+
def show(depth=1)
|
298
|
+
crnt = [tree]
|
299
|
+
(depth.to_i-1).times do
|
300
|
+
crnt = crnt.map { |node| node.children.values }.flatten # descend to next depth
|
301
|
+
end
|
302
|
+
display_adjacent(*crnt.map(&method(:colour_if_complete)))
|
303
|
+
end
|
304
|
+
|
305
|
+
def back
|
306
|
+
self.tree = tree.parent || raise("Can't go back, this is where we started")
|
307
|
+
end
|
308
|
+
|
309
|
+
def rate(player_number)
|
310
|
+
puts tree.rating_for(player_number.to_i)
|
311
|
+
end
|
312
|
+
|
313
|
+
def exit
|
314
|
+
Kernel.exit
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
TTT::ExploreTree.new.explore!
|
320
|
+
end
|
321
|
+
|
322
|
+
end
|
323
|
+
|
324
|
+
|
data/Readme.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
T(ic) T(ac) T(oe)
|
2
|
+
=================
|
3
|
+
|
4
|
+
TTT is a Tic Tac Toe lib, as well and two interfaces to play it.
|
5
|
+
|
6
|
+
|
7
|
+
Features
|
8
|
+
--------
|
9
|
+
|
10
|
+
* An aggressive computer player that will never lose
|
11
|
+
* A command line interface that will work in any terminal
|
12
|
+
* A GUI interface written with [Limelight][limelight]
|
13
|
+
|
14
|
+
|
15
|
+
Requirements
|
16
|
+
------------
|
17
|
+
|
18
|
+
* FIXME (list of requirements)
|
19
|
+
|
20
|
+
|
21
|
+
Install
|
22
|
+
-------
|
23
|
+
|
24
|
+
* `gem install ttt`
|
25
|
+
* `gem install limelight` (you must be on jruby)
|
26
|
+
|
27
|
+
|
28
|
+
Author
|
29
|
+
------
|
30
|
+
|
31
|
+
[Josh Cheek](joshcheek)
|
32
|
+
|
33
|
+
|
34
|
+
[limelight]: http://limelight.8thlight.com/
|
35
|
+
[joshcheek]: http://joshcheek.com/
|
data/bin/ttt
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
Feature: Binary
|
2
|
+
In order to interact with the interfaces
|
3
|
+
As a player
|
4
|
+
I want a binary where I can specify how I should be able to interact
|
5
|
+
|
6
|
+
Scenario: It is a binary
|
7
|
+
Given I look at bin/ttt
|
8
|
+
Then I see it is executable
|
9
|
+
|
10
|
+
Scenario: -h
|
11
|
+
Given I pass the it "-h" on the command line
|
12
|
+
Then it should display /^Usage/
|
13
|
+
|
14
|
+
Scenario: --help
|
15
|
+
Given I pass the it "--help" on the command line
|
16
|
+
Then it should display /^Usage/
|
17
|
+
|
18
|
+
Scenario: no input displays help
|
19
|
+
Given I pass the it "" on the command line
|
20
|
+
Then it should display /^Usage/
|
21
|
+
|
22
|
+
Scenario: -i without an arg
|
23
|
+
Given I pass the it "-i" on the command line
|
24
|
+
Then it should print /missing argument: -i/ to stderr
|
25
|
+
And it should exit with code of 1
|
26
|
+
|
27
|
+
|
28
|
+
Scenario: --interface, without an arg
|
29
|
+
Given I pass the it "--interface" on the command line
|
30
|
+
Then it should print /missing argument: --interface/ to stderr
|
31
|
+
And it should exit with code of 1
|
32
|
+
|
33
|
+
Scenario: -i cli
|
34
|
+
Given I pass the it "-i cli" on the command line
|
35
|
+
Then it should welcome me to Tic Tac Toe
|
36
|
+
|
37
|
+
Scenario: -i not_real_interface
|
38
|
+
Given I pass the it "-i not_real_interface" on the command line
|
39
|
+
Then it should print /"not_real_interface" is not a valid interface/ to stderr
|