sudokusolver 1.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.
data/COPYING ADDED
@@ -0,0 +1 @@
1
+ See the file called LICENSE
@@ -0,0 +1 @@
1
+ 2007-04-09 Version 0.1 => initial release
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2007
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,20 @@
1
+ This sofware was translated from the python source code
2
+ obtained from Peter Norvig's website:
3
+
4
+ http://www.norvig.com/sudoku.html
5
+ http://www.norvig.com/sudo.py
6
+
7
+ Thank you to Peter Norvig for the original python source code,
8
+ algorithms and exceptionally clear explanations.
9
+
10
+ example:
11
+ ========
12
+
13
+ require 'sudoku_solver'
14
+
15
+ # The puzzle representation is simply the 9 rows of the Sudoku grid stringed together
16
+ # from top to bottom (periods representing blank squares)
17
+
18
+ puzzle = "4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......"
19
+ s = SudokuSolver.new
20
+ s.print_grid(s.search(s.parse_grid(puzzle)))
@@ -0,0 +1,256 @@
1
+ # Rakefile
2
+ require "rake/testtask"
3
+ require "rake/clean"
4
+ require "rake/rdoctask"
5
+ require "rake/gempackagetask"
6
+
7
+ #---
8
+ # The name of your project
9
+ PROJECT = "SudokuSolver"
10
+
11
+ # Your name, used in packaging.
12
+ MY_NAME = "Martin-Louis Bright"
13
+
14
+ # Your email address, used in packaging.
15
+ MY_EMAIL = "mlbright@gmail.com"
16
+
17
+ # Short summary of your project, used in packaging.
18
+ PROJECT_SUMMARY = "Commandline program and library for solving Sudoku puzzles"
19
+
20
+ # The project's package name (as opposed to its display name). Used for
21
+ # RubyForge connectivity and packaging.
22
+ UNIX_NAME = "sudokusolver"
23
+
24
+ # Your RubyForge user name.
25
+ RUBYFORGE_USER = ENV["RUBYFORGE_USER"] || "mlbright"
26
+
27
+ # Directory on RubyForge where your website's files should be uploaded.
28
+ WEBSITE_DIR = "sudokusolver"
29
+
30
+ # Output directory for the rdoc html files.
31
+ # If you don't have a custom homepage, and want to use the RDoc
32
+ # index.html as homepage, just set it to WEBSITE_DIR.
33
+ RDOC_HTML_DIR = "#{WEBSITE_DIR}/rdoc"
34
+
35
+ #---
36
+ # Variable settings for extension support.
37
+ EXT_DIR = "ext"
38
+ HAVE_EXT = File.directory?(EXT_DIR)
39
+ EXTCONF_FILES = FileList["#{EXT_DIR}/**/extconf.rb"]
40
+ EXT_SOURCES = FileList["#{EXT_DIR}/**/*.{c,h}"]
41
+ # Eventually add other files from EXT_DIR, like "MANIFEST"
42
+ EXT_DIST_FILES = EXT_SOURCES + EXTCONF_FILES
43
+
44
+ #---
45
+ REQUIRE_PATHS = ["lib"]
46
+ REQUIRE_PATHS << EXT_DIR if HAVE_EXT
47
+ $LOAD_PATH.concat(REQUIRE_PATHS)
48
+ # This library file defines the MyProject::VERSION constant.
49
+ require "#{UNIX_NAME}"
50
+ PROJECT_VERSION = eval("#{PROJECT}::VERSION") # e.g. "1.0.2"
51
+
52
+ #---
53
+ # Clobber object files and Makefiles generated by extconf.rb.
54
+ CLOBBER.include("#{EXT_DIR}/**/*.{so,dll,o}", "#{EXT_DIR}/**/Makefile")
55
+ # Clobber .config generated by setup.rb.
56
+ CLOBBER.include(".config")
57
+
58
+ #---
59
+ # Options common to RDocTask AND Gem::Specification.
60
+ # The --main argument specifies which file appears on the index.html page
61
+ GENERAL_RDOC_OPTS = {
62
+ "--title" => "#{PROJECT} API documentation",
63
+ "--main" => "README.rdoc"
64
+ }
65
+
66
+ # Additional RDoc formatted files, besides the Ruby source files.
67
+ RDOC_FILES = FileList["README.rdoc", "Changes.rdoc"]
68
+ # Remove the following line if you don't want to extract RDoc from
69
+ # the extension C sources.
70
+ RDOC_FILES.include(EXT_SOURCES)
71
+
72
+ # Ruby library code.
73
+ LIB_FILES = FileList["lib/**/*.rb"]
74
+
75
+ # Filelist with Test::Unit test cases.
76
+ TEST_FILES = FileList["test/**/tc_*.rb"]
77
+
78
+ # Executable scripts, all non-garbage files under bin/.
79
+ BIN_FILES = FileList["bin/*"]
80
+
81
+ # This filelist is used to create source packages.
82
+ # Include all Ruby and RDoc files.
83
+ DIST_FILES = FileList["**/*.rb", "**/*.rdoc"]
84
+ DIST_FILES.include("Rakefile", "COPYING", "LICENSE")
85
+ DIST_FILES.include(BIN_FILES)
86
+ DIST_FILES.include("data/**/*", "test/data/**/*")
87
+ DIST_FILES.include("#{WEBSITE_DIR}/**/*.{html,css}", "man/*.[0-9]")
88
+ # Don't package files which are autogenerated by RDocTask
89
+ DIST_FILES.exclude(/^(\.\/)?#{RDOC_HTML_DIR}(\/|$)/)
90
+ # Include extension source files.
91
+ DIST_FILES.include(EXT_DIST_FILES)
92
+ # Don't package temporary files, perhaps created by tests.
93
+ DIST_FILES.exclude("**/temp_*", "**/*.tmp")
94
+ # Don't get into recursion...
95
+ DIST_FILES.exclude(/^(\.\/)?pkg(\/|$)/)
96
+
97
+ #---
98
+ # Run the tests if rake is invoked without arguments.
99
+ task "default" => ["test"]
100
+
101
+ test_task_name = HAVE_EXT ? "run-tests" : "test"
102
+ Rake::TestTask.new(test_task_name) do |t|
103
+ t.test_files = TEST_FILES
104
+ t.libs = REQUIRE_PATHS
105
+ end
106
+
107
+ #---
108
+ # Set an environment variable with any configuration options you want to
109
+ # be passed through to "setup.rb config".
110
+ CONFIG_OPTS = ENV["CONFIG"]
111
+ if HAVE_EXT
112
+ file_create ".config" do
113
+ ruby "setup.rb config #{CONFIG_OPTS}"
114
+ end
115
+
116
+ desc "Configure and make extension. " +
117
+ "The CONFIG variable is passed to `setup.rb config'"
118
+ task "make-ext" => ".config" do
119
+ # The -q option suppresses messages from setup.rb.
120
+ ruby "setup.rb -q setup"
121
+ end
122
+
123
+ desc "Run tests after making the extension."
124
+ task "test" do
125
+ Rake::Task["make-ext"].invoke
126
+ Rake::Task["run-tests"].invoke
127
+ end
128
+ end
129
+
130
+ #---
131
+ # The "rdoc" task generates API documentation.
132
+ Rake::RDocTask.new("rdoc") do |t|
133
+ t.rdoc_files = RDOC_FILES + LIB_FILES
134
+ t.title = GENERAL_RDOC_OPTS["--title"]
135
+ t.main = GENERAL_RDOC_OPTS["--main"]
136
+ t.rdoc_dir = RDOC_HTML_DIR
137
+ end
138
+
139
+ #---
140
+ GEM_SPEC = Gem::Specification.new do |s|
141
+ s.name = UNIX_NAME
142
+ s.version = PROJECT_VERSION
143
+ s.summary = PROJECT_SUMMARY
144
+ s.rubyforge_project = UNIX_NAME
145
+ s.homepage = "http://#{UNIX_NAME}.rubyforge.org/"
146
+ s.author = MY_NAME
147
+ s.email = MY_EMAIL
148
+ s.files = DIST_FILES
149
+ s.test_files = TEST_FILES
150
+ s.executables = BIN_FILES.map { |fn| File.basename(fn) }
151
+ s.has_rdoc = true
152
+ s.extra_rdoc_files = RDOC_FILES
153
+ s.rdoc_options = GENERAL_RDOC_OPTS.to_a.flatten
154
+ if HAVE_EXT
155
+ s.extensions = EXTCONF_FILES
156
+ s.require_paths << EXT_DIR
157
+ end
158
+ end
159
+
160
+ # Now we can generate the package-related tasks.
161
+ Rake::GemPackageTask.new(GEM_SPEC) do |pkg|
162
+ pkg.need_zip = true
163
+ pkg.need_tar = true
164
+ end
165
+
166
+ #---
167
+ desc "Upload website to RubyForge. " +
168
+ "scp will prompt for your RubyForge password."
169
+ task "publish-website" => ["rdoc"] do
170
+ rubyforge_path = "/var/www/gforge-projects/#{UNIX_NAME}/"
171
+ sh "scp -r #{WEBSITE_DIR}/* " +
172
+ "#{RUBYFORGE_USER}@rubyforge.org:#{rubyforge_path}",
173
+ :verbose => true
174
+ end
175
+
176
+ #---
177
+ task "rubyforge-setup" do
178
+ unless File.exist?(File.join(ENV["HOME"], ".rubyforge"))
179
+ puts "rubyforge will ask you to edit its config.yml now."
180
+ puts "Please set the `username' and `password' entries"
181
+ puts "to your RubyForge username and RubyForge password!"
182
+ puts "Press ENTER to continue."
183
+ $stdin.gets
184
+ sh "rubyforge setup", :verbose => true
185
+ end
186
+ end
187
+
188
+ task "rubyforge-login" => ["rubyforge-setup"] do
189
+ # Note: We assume that username and password were set in
190
+ # rubyforge's config.yml.
191
+ sh "rubyforge login", :verbose => true
192
+ end
193
+
194
+ task "publish-packages" => ["package", "rubyforge-login"] do
195
+ # Upload packages under pkg/ to RubyForge
196
+ # This task makes some assumptions:
197
+ # * You have already created a package on the "Files" tab on the
198
+ # RubyForge project page. See pkg_name variable below.
199
+ # * You made entries under package_ids and group_ids for this
200
+ # project in rubyforge's config.yml. If not, eventually read
201
+ # "rubyforge --help" and then run "rubyforge setup".
202
+ pkg_name = ENV["PKG_NAME"] || UNIX_NAME
203
+ cmd = "rubyforge add_release #{UNIX_NAME} #{pkg_name} " +
204
+ "#{PROJECT_VERSION} #{UNIX_NAME}-#{PROJECT_VERSION}"
205
+ cd "pkg" do
206
+ sh(cmd + ".gem", :verbose => true)
207
+ sh(cmd + ".tgz", :verbose => true)
208
+ sh(cmd + ".zip", :verbose => true)
209
+ end
210
+ end
211
+
212
+ #---
213
+ # The "prepare-release" task makes sure your tests run, and then generates
214
+ # files for a new release.
215
+ desc "Run tests, generate RDoc and create packages."
216
+ task "prepare-release" => ["clobber"] do
217
+ puts "Preparing release of #{PROJECT} version #{VERSION}"
218
+ Rake::Task["test"].invoke
219
+ Rake::Task["rdoc"].invoke
220
+ Rake::Task["package"].invoke
221
+ end
222
+
223
+ # The "publish" task is the overarching task for the whole project. It
224
+ # builds a release and then publishes it to RubyForge.
225
+ desc "Publish new release of #{PROJECT}"
226
+ task "publish" => ["prepare-release"] do
227
+ puts "Uploading documentation..."
228
+ Rake::Task["publish-website"].invoke
229
+ puts "Checking for rubyforge command..."
230
+ `rubyforge --help`
231
+ if $? == 0
232
+ puts "Uploading packages..."
233
+ Rake::Task["publish-packages"].invoke
234
+ puts "Release done!"
235
+ else
236
+ puts "Can't invoke rubyforge command."
237
+ puts "Either install rubyforge with 'gem install rubyforge'"
238
+ puts "and retry or upload the package files manually!"
239
+ end
240
+ end
241
+
242
+ #---
243
+ # $ rake -T
244
+ # rake clean # Remove any temporary products.
245
+ # rake clobber # Remove any generated file.
246
+ # rake clobber_package # Remove package products
247
+ # rake clobber_rdoc # Remove rdoc products
248
+ # rake package # Build all the packages
249
+ # rake prepare-release # Run tests, generate RDoc and create packages.
250
+ # rake publish # Publish new release of MyProject
251
+ # rake publish-website # Upload website to RubyForge. scp will prompt for your RubyForge password.
252
+ # rake rdoc # Build the rdoc HTML Files
253
+ # rake repackage # Force a rebuild of the package files
254
+ # rake rerdoc # Force a rebuild of the RDOC files
255
+ # rake test # Run tests for test
256
+ #---
@@ -0,0 +1,197 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Translated into ruby from python by Martin-Louis Bright
4
+ # Algorithm, overall structure and original python source code by Peter Norvig
5
+ # See http://norvig.com/sudoku.html
6
+
7
+ ## Throughout this program:
8
+ ## r is a row, e.g. 'A'
9
+ ## c is a column, e.g. '3'
10
+ ## s is a square, e.g. 'A3'
11
+ ## d is a digit, e.g. '9'
12
+ ## u is a unit, e.g. ['A1','B1','C1','D1','E1','F1','G1','H1','I1']
13
+ ## g is a grid, e.g. 81 non-blank chars, e.g. starting with '.18...7...
14
+ ## values is a hash of possible values, e.g. {'A1':'123489', 'A2':'8', ...}
15
+
16
+ class SudokuSolver
17
+ VERSION = "1.0"
18
+ attr_reader :rows, :cols, :squares, :unitlist, :peers, :units
19
+
20
+ def cross(a, b)
21
+ cp = Array.new # cross product
22
+ a.each do |x|
23
+ b.each do |y|
24
+ cp << x+y
25
+ end
26
+ end
27
+ return cp
28
+ end
29
+
30
+ def initialize()
31
+ @rows = ('A'..'I').to_a
32
+ @cols = ('1'..'9').to_a
33
+ @squares = cross(@rows, @cols)
34
+ @unitlist = Array.new
35
+ cols.each { |c| @unitlist.push(cross(rows, c)) }
36
+ rows.each { |r| @unitlist.push(cross(r, cols)) }
37
+ for rb in ['ABC','DEF','GHI'] do
38
+ for cb in ['123','456','789'] do
39
+ @unitlist << cross(rb.split(''),cb.split(''))
40
+ end
41
+ end
42
+
43
+ @units = Hash.new
44
+ squares.each do |s|
45
+ @units[s] = Array.new
46
+ unitlist.each do |u|
47
+ u.each do |x|
48
+ @units[s].push(u) if s == x
49
+ end
50
+ end
51
+ end
52
+
53
+ @peers = Hash.new
54
+ squares.each do |s|
55
+ @peers[s] = Array.new
56
+ units[s].each do |u|
57
+ u.each { |s2| @peers[s] << s2 if s2 != s }
58
+ end
59
+ end
60
+
61
+ end
62
+
63
+ def parse_grid(g)
64
+ g = g.chomp
65
+ g = g.split('')
66
+ values = Hash.new
67
+ # Initially any square can be anything.
68
+ squares.each { |s| values[s] = "123456789" }
69
+ for s,d in squares.zip(g)
70
+ return false unless assign(values, s, d) if d =~ /\d/
71
+ end
72
+ return values
73
+ end
74
+
75
+ def assign(values, s, d)
76
+ values[s].split('').each do |d2|
77
+ unless d2 == d
78
+ return false if eliminate(values, s, d2) == false
79
+ end
80
+ end
81
+ return values
82
+ end
83
+
84
+ def eliminate(values, s, d)
85
+ return values unless values[s].include?(d) ## Already eliminated.
86
+
87
+ values[s] = values[s].sub(d,'') ## Remove the digit from the string of possibilities
88
+ ## values[s].sub!(d,'') => why doesn't sub!() work?
89
+
90
+ return false if values[s].length == 0 ## Contradiction: no more values (no more digits can be assigned)
91
+
92
+ ## Remove digit from all peers
93
+ peers[s].each { |s2| return false unless eliminate(values, s2, values[s]) } if values[s].length == 1
94
+
95
+ ## Assign digit if, by elimination, there is only one square left
96
+ ## in the units for this square that can hold the digit
97
+ units[s].each do |u|
98
+ dplaces = Array.new
99
+ u.each { |s2| dplaces << s2 if values[s2].include?(d) }
100
+ return false if dplaces.length == 0 # bad
101
+ return false if assign(values, dplaces[0], d) == false if dplaces.length == 1
102
+ end
103
+ return values
104
+ end
105
+
106
+ def search(values)
107
+ return false if values == false
108
+
109
+ solved = true ## assumption
110
+ squares.each do |s|
111
+ unless values[s].length == 1
112
+ solved = false
113
+ break
114
+ end
115
+ end
116
+ return values if solved == true ## Solved!
117
+
118
+ min = 10
119
+ start = nil
120
+ squares.each do |s| ## Chose the undetermined square s with the fewest possibilities
121
+ l = values[s].length
122
+ if l > 1 && l < min
123
+ min = l
124
+ start = s
125
+ end
126
+ end
127
+
128
+ values[start].split('').each do |d|
129
+ solution = search(assign(values.clone,start,d))
130
+ return solution unless solution == false
131
+ end
132
+ return false
133
+ end
134
+
135
+ def print_grid(values)
136
+ return if values == false
137
+ max = 0
138
+ squares.each { |s| max = values[s].length if values[s].length > max }
139
+ width = 1 + max
140
+ a = Array.new
141
+ 3.times do |c|
142
+ tmp = ""
143
+ (3*width).times do
144
+ tmp = tmp + '-'
145
+ end
146
+ tmp += "-" if c == 1
147
+ a.push(tmp)
148
+ end
149
+ line = "\n" + a.join('+')
150
+
151
+ tmp = ""
152
+ for r in rows
153
+ for c in cols
154
+ tmp = tmp + values[r+c].center(width)
155
+ if c == '3' or c == '6'
156
+ tmp = tmp + '| '
157
+ end
158
+ end
159
+ tmp = tmp + line if r == 'C' or r == 'F'
160
+ tmp = tmp + "\n"
161
+ end
162
+ puts tmp + "\n"
163
+ return values
164
+ end
165
+
166
+ def string_solution(values)
167
+ solution = ""
168
+ squares.each do |s|
169
+ solution += values[s]
170
+ end
171
+ return solution
172
+ end
173
+
174
+ def check_solution(solution)
175
+ values = Hash.new
176
+ for s,d in squares.zip(solution.split(''))
177
+ values[s] = d
178
+ end
179
+
180
+ unitlist.each do |u|
181
+ tmp = Hash.new
182
+ u.each do |s|
183
+ tmp[values[s]] = true
184
+ end
185
+ return false unless tmp.keys.length == 9
186
+ end
187
+ return true
188
+ end
189
+
190
+ end
191
+
192
+ ## Algorithm by Peter Norvig @ http://www.norvig.com/sudoku.html
193
+
194
+ ## More constraints:
195
+ ## http://www.scanraid.com/BasicStrategies.htm
196
+ ## http://www.krazydad.com/blog/2005/09/29/an-index-of-sudoku-strategies/
197
+ ## http://www2.warwick.ac.uk/fac/sci/moac/currentstudents/peter_cock/python/sudoku/
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created by Martin-Louis Bright on 2007-04-10.
4
+ # Copyright (c) 2007. All rights reserved.
5
+
6
+ require 'sudokusolver'
7
+
8
+ puzzle = "4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......"
9
+ s = SudokuSolver.new
10
+ s.print_grid(s.search(s.parse_grid(puzzle)))
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created by Martin-Louis Bright on 2007-03-21.
4
+ # Copyright (c) 2007. All rights reserved.
5
+
6
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'sudokusolver')
7
+ require 'test/unit'
8
+
9
+ class SudokuTest < Test::Unit::TestCase
10
+
11
+ def setup
12
+ @path = File.join(File.dirname(__FILE__), '..')
13
+ @easy = File.read(@path + '/test/easy_puzzles.txt').split("\n")
14
+ @hard = File.read(@path + '/test/top95.txt').split("\n")
15
+ @s = SudokuSolver.new
16
+ end
17
+
18
+ def test_empty_puzzle
19
+ e = "................................................................................."
20
+ sol = @s.string_solution(@s.search(@s.parse_grid(e)))
21
+ puts sol
22
+ assert(@s.check_solution(sol))
23
+ end
24
+
25
+ def test_sanity
26
+ puts "Easy puzzle (constraint satisfaction only): "
27
+ puts
28
+ @s.print_grid(@s.search(@s.parse_grid(@easy[0])))
29
+ puts "Hard puzzle (constraint satisfaction + search): "
30
+ puts
31
+ @s.print_grid(@s.search(@s.parse_grid(@hard[0])))
32
+ end
33
+
34
+ def test_easy
35
+ multiple(@easy)
36
+ end
37
+
38
+ def test_hard
39
+ multiple(@hard)
40
+ end
41
+
42
+ def test_bmark_hard
43
+ @hard.each do |g|
44
+ puts @s.string_solution(@s.search(@s.parse_grid(g)))
45
+ end
46
+ end
47
+
48
+ def multiple(puzzles)
49
+ puzzles.each do |g|
50
+ assert(@s.check_solution(@s.string_solution(@s.search(@s.parse_grid(g)))))
51
+ end
52
+ end
53
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.2
3
+ specification_version: 1
4
+ name: sudokusolver
5
+ version: !ruby/object:Gem::Version
6
+ version: "1.0"
7
+ date: 2007-04-15 00:00:00 -04:00
8
+ summary: Commandline program and library for solving Sudoku puzzles
9
+ require_paths:
10
+ - lib
11
+ email: mlbright@gmail.com
12
+ homepage: http://sudokusolver.rubyforge.org/
13
+ rubyforge_project: sudokusolver
14
+ description:
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Martin-Louis Bright
31
+ files:
32
+ - lib/sudokusolver.rb
33
+ - test/driver.rb
34
+ - test/tc_sudoku.rb
35
+ - Changes.rdoc
36
+ - README.rdoc
37
+ - Rakefile
38
+ - COPYING
39
+ - LICENSE
40
+ test_files:
41
+ - test/tc_sudoku.rb
42
+ rdoc_options:
43
+ - --title
44
+ - SudokuSolver API documentation
45
+ - --main
46
+ - README.rdoc
47
+ extra_rdoc_files:
48
+ - README.rdoc
49
+ - Changes.rdoc
50
+ executables: []
51
+
52
+ extensions: []
53
+
54
+ requirements: []
55
+
56
+ dependencies: []
57
+