sudokusolver_ng 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bab3bb7004fd538bbae6ff152f7e63342bcc3de9
4
+ data.tar.gz: adfdadd1bf26701147c1b2d14b8d3629a63a6ee7
5
+ SHA512:
6
+ metadata.gz: 2bb58f45c66d4808dcafb6ad17943e72ead7760125af3c69c5d6970689891b4dbb66a5f3f87cbe8334707ced4d390c1ae5351caa2d6ccd44618a0b3e34ca759b
7
+ data.tar.gz: 70d465640329480d528d31254908b7083db94fca96876330961b8bcf7a5b0223d9a981c7ee7b7f01e5940433c510f12fa91626f24658bb8275de80ffff6a25f3
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.0
4
+ - 2.1.0
5
+ - 2.0.0
6
+ - 1.9.3
7
+ - 1.8.7
8
+ - jruby-18mode
9
+ - jruby-19mode
10
+ - rbx-2
11
+ - ruby-head
12
+ - jruby-head
13
+ - ree
data/COPYING ADDED
@@ -0,0 +1 @@
1
+ See the file called LICENSE
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sudokusolver.gemspec
4
+ gemspec
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.
data/README.md ADDED
@@ -0,0 +1,40 @@
1
+ sudokusolver_ng
2
+ ============
3
+
4
+ Commandline program and library for solving Sudoku puzzles
5
+
6
+ [![Build Status](https://travis-ci.org/kaspergrubbe/sudokusolver_ng.svg?branch=master)](https://travis-ci.org/kaspergrubbe/sudokusolver_ng)
7
+
8
+ ## History
9
+
10
+ This software was translated from the python source code obtained from Peter Norvig's website:
11
+
12
+ http://www.norvig.com/sudoku.html
13
+ http://www.norvig.com/sudo.py
14
+
15
+ Thank you to Peter Norvig for the original python source code, algorithms and exceptionally clear explanations.
16
+
17
+ All this work was done by Martin-Louis Bright, and then gemified and converted to Ruby 1.9 by Kasper Grubbe. The original project is called "sudokusolver" and is available from Rubygems here: https://rubygems.org/gems/sudokusolver, this is a fork moved to Github.
18
+
19
+ ## Install
20
+
21
+ Add this to your `Gemfile`:
22
+
23
+ ```ruby
24
+ gem 'sudokusolver_ng'
25
+ ```
26
+
27
+ And remember to `bundle`
28
+
29
+ ## Usage
30
+
31
+ ```ruby
32
+ require 'sudokusolver_ng'
33
+
34
+ # The puzzle representation is simply the 9 rows of the Sudoku grid stringed together
35
+ # from top to bottom (periods representing blank squares)
36
+
37
+ puzzle = "4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......"
38
+ s = SudokuSolverNg.new
39
+ s.print_grid(s.search(s.parse_grid(puzzle)))
40
+ ```
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'rake'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,212 @@
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
+ # Algorithm by Peter Norvig @ http://www.norvig.com/sudoku.html
17
+
18
+ # More constraints:
19
+ # http://www.scanraid.com/BasicStrategies.htm
20
+ # http://www.krazydad.com/blog/2005/09/29/an-index-of-sudoku-strategies/
21
+ # http://www2.warwick.ac.uk/fac/sci/moac/currentstudents/peter_cock/python/sudoku/
22
+
23
+ class SudokuSolverNg
24
+ VERSION = "2.0.0"
25
+
26
+ attr_reader :rows, :cols, :squares, :unitlist, :peers, :units
27
+
28
+ # Cross-product
29
+ def cross(a, b)
30
+ cp = Array.new # cross product
31
+ a.each do |x|
32
+ b.each do |y|
33
+ cp << x+y
34
+ end
35
+ end
36
+ return cp
37
+ end
38
+
39
+ def initialize()
40
+ @rows = ('A'..'I').to_a
41
+ @cols = ('1'..'9').to_a
42
+ @squares = cross(@rows, @cols)
43
+ @unitlist = Array.new
44
+ cols.each { |c| @unitlist.push(cross(rows, [c])) }
45
+ rows.each { |r| @unitlist.push(cross([r], cols)) }
46
+ for rb in ['ABC','DEF','GHI'] do
47
+ for cb in ['123','456','789'] do
48
+ @unitlist << cross(rb.split(''),cb.split(''))
49
+ end
50
+ end
51
+
52
+ @units = Hash.new
53
+ squares.each do |s|
54
+ @units[s] = Array.new
55
+ unitlist.each do |u|
56
+ u.each do |x|
57
+ @units[s].push(u) if s == x
58
+ end
59
+ end
60
+ end
61
+
62
+ @peers = Hash.new
63
+ squares.each do |s|
64
+ @peers[s] = Array.new
65
+ units[s].each do |u|
66
+ u.each { |s2| @peers[s] << s2 if s2 != s }
67
+ end
68
+ end
69
+
70
+ end
71
+
72
+ # A grid is an 81 character string composed of the digits 0-9
73
+ # A blank is represented as a period.
74
+ def parse_grid(g)
75
+ g = g.chomp
76
+ g = g.split('')
77
+ values = Hash.new
78
+ # Initially any square can be anything.
79
+ squares.each { |s| values[s] = "123456789" }
80
+ for s,d in squares.zip(g)
81
+ return false unless assign(values, s, d) if d =~ /\d/
82
+ end
83
+ return values
84
+ end
85
+
86
+ # Assign a value to a square in the Sudoku grid:
87
+ # Eliminate all other possible digits from the square
88
+ # by calling the eliminate function (mutually recursive)
89
+ def assign(values, s, d)
90
+ values[s].split('').each do |d2|
91
+ unless d2 == d
92
+ return false if eliminate(values, s, d2) == false
93
+ end
94
+ end
95
+ return values
96
+ end
97
+
98
+ # Remove a possibility from a square.
99
+ # Recursively propagate the constraints: look at the source code for how this is done.
100
+ def eliminate(values, s, d)
101
+ return values unless values[s].include?(d) ## Already eliminated.
102
+
103
+ values[s] = values[s].sub(d,'') # Remove the digit from the string of possibilities
104
+ # values[s].sub!(d,'') => why doesn't sub!() work?
105
+
106
+ return false if values[s].length == 0 # Contradiction: no more values (no more digits can be assigned)
107
+
108
+ # Remove digit from all peers
109
+ # If the square has only one remaining possibility, that is the assigned value for the square and
110
+ # that value must be removed from all that square's peers.
111
+ peers[s].each { |s2| return false unless eliminate(values, s2, values[s]) } if values[s].length == 1
112
+
113
+ # Assign the digit to the square if, by elimination
114
+ # this is the only square that has the digit as a possibility
115
+ units[s].each do |u|
116
+ dplaces = Array.new
117
+ u.each { |s2| dplaces << s2 if values[s2].include?(d) }
118
+ return false if dplaces.length == 0 # bad
119
+ return false if assign(values, dplaces[0], d) == false if dplaces.length == 1
120
+ end
121
+ return values
122
+ end
123
+
124
+ # Search if constraint satisfaction does not solve the puzzle
125
+ def search(values)
126
+ return false if values == false
127
+
128
+ solved = true # assumption
129
+ squares.each do |s|
130
+ unless values[s].length == 1
131
+ solved = false
132
+ break
133
+ end
134
+ end
135
+ return values if solved == true ## Solved!
136
+
137
+ min = 10
138
+ start = nil
139
+ squares.each do |s| # Chose the undetermined square s with the fewest possibilities
140
+ l = values[s].length
141
+ if l > 1 && l < min
142
+ min = l
143
+ start = s
144
+ end
145
+ end
146
+
147
+ values[start].split('').each do |d|
148
+ solution = search(assign(values.clone,start,d))
149
+ return solution unless solution == false
150
+ end
151
+ return false
152
+ end
153
+
154
+ # Print a text Sudoku grid to STDOUT
155
+ def print_grid(values)
156
+ return if values == false
157
+ max = 0
158
+ squares.each { |s| max = values[s].length if values[s].length > max }
159
+ width = 1 + max
160
+ a = Array.new
161
+ 3.times do |c|
162
+ tmp = ""
163
+ (3*width).times do
164
+ tmp = tmp + '-'
165
+ end
166
+ tmp += "-" if c == 1
167
+ a.push(tmp)
168
+ end
169
+ line = "\n" + a.join('+')
170
+
171
+ tmp = ""
172
+ for r in rows
173
+ for c in cols
174
+ tmp = tmp + values[r+c].center(width)
175
+ if c == '3' or c == '6'
176
+ tmp = tmp + '| '
177
+ end
178
+ end
179
+ tmp = tmp + line if r == 'C' or r == 'F'
180
+ tmp = tmp + "\n"
181
+ end
182
+ puts tmp + "\n"
183
+ return values
184
+ end
185
+
186
+ # Transform the solution into an 81 character string
187
+ def string_solution(values)
188
+ solution = ""
189
+ squares.each do |s|
190
+ solution += values[s]
191
+ end
192
+ return solution
193
+ end
194
+
195
+ # Verify the Sudoku solution
196
+ def check_solution(solution)
197
+ values = Hash.new
198
+ for s,d in squares.zip(solution.split(''))
199
+ values[s] = d
200
+ end
201
+
202
+ unitlist.each do |u|
203
+ tmp = Hash.new
204
+ u.each do |s|
205
+ tmp[values[s]] = true
206
+ end
207
+ return false unless tmp.keys.length == 9
208
+ end
209
+ return true
210
+ end
211
+
212
+ end
@@ -0,0 +1,50 @@
1
+ ..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82....26.95..8..2.3..9..5.1.3..
2
+ 2...8.3...6..7..84.3.5..2.9...1.54.8.........4.27.6...3.1..7.4.72..4..6...4.1...3
3
+ ......9.7...42.18....7.5.261..9.4....5.....4....5.7..992.1.8....34.59...5.7......
4
+ .3..5..4...8.1.5..46.....12.7.5.2.8....6.3....4.1.9.3.25.....98..1.2.6...8..6..2.
5
+ .2.81.74.7....31...9...28.5..9.4..874..2.8..316..3.2..3.27...6...56....8.76.51.9.
6
+ 1..92....524.1...........7..5...81.2.........4.27...9..6...........3.945....71..6
7
+ .43.8.25.6.............1.949....4.7....6.8....1.2....382.5.............5.34.9.71.
8
+ 48...69.2..2..8..19..37..6.84..1.2....37.41....1.6..49.2..85..77..9..6..6.92...18
9
+ ...9....2.5.1234...3....16.9.8.......7.....9.......2.5.91....5...7439.2.4....7...
10
+ ..19....39..7..16..3...5..7.5......9..43.26..2......7.6..1...3..42..7..65....68..
11
+ ...1254....84.....42.8......3.....95.6.9.2.1.51.....6......3.49.....72....1298...
12
+ .6234.75.1....56..57.....4.....948..4.......6..583.....3.....91..64....7.59.8326.
13
+ 3..........5..9...2..5.4....2....7..16.....587.431.6.....89.1......67.8......5437
14
+ 63..........5....8..5674.......2......34.1.2.......345.....7..4.8.3..9.29471...8.
15
+ ....2..4...8.35.......7.6.2.31.4697.2...........5.12.3.49...73........1.8....4...
16
+ 361.259...8.96..1.4......57..8...471...6.3...259...8..74......5.2..18.6...547.329
17
+ .5.8.7.2.6...1..9.7.254...6.7..2.3.15.4...9.81.3.8..7.9...762.5.6..9...3.8.1.3.4.
18
+ .8...5........3457....7.8.9.6.4..9.3..7.1.5..4.8..7.2.9.1.2....8423........1...8.
19
+ ..35.29......4....1.6...3.59..251..8.7.4.8.3.8..763..13.8...1.4....2......51.48..
20
+ ...........98.51...519.742.29.4.1.65.........14.5.8.93.267.958...51.36...........
21
+ .2..3..9....9.7...9..2.8..5..48.65..6.7...2.8..31.29..8..6.5..7...3.9....3..2..5.
22
+ ..5.....6.7...9.2....5..1.78.415.......8.3.......928.59.7..6....3.4...1.2.....6..
23
+ .4.....5...19436....9...3..6...5...21.3...5.68...2...7..5...2....24367...3.....4.
24
+ ..4..........3...239.7...8.4....9..12.98.13.76..2....8.1...8.539...4..........8..
25
+ 36..2..89...361............8.3...6.24..6.3..76.7...1.8............418...97..3..14
26
+ 5..4...6...9...8..64..2.........1..82.8...5.17..5.........9..84..3...6...6...3..2
27
+ ..72564..4.......5.1..3..6....5.8.....8.6.2.....1.7....3..7..9.2.......4..63127..
28
+ ..........79.5.18.8.......7..73.68..45.7.8.96..35.27..7.......5.16.3.42..........
29
+ .3.....8...9...5....75.92..7..1.5..8.2..9..3.9..4.2..1..42.71....2...8...7.....9.
30
+ 2..17.6.3.5....1.......6.79....4.7.....8.1.....9.5....31.4.......5....6.9.6.37..2
31
+ .......8.8..7.1.4..4..2..3.374...9......3......5...321.1..6..5..5.8.2..6.8.......
32
+ .......85...21...996..8.1..5..8...16.........89...6..7..9.7..523...54...48.......
33
+ 6.8.7.5.2.5.6.8.7...2...3..5...9...6.4.3.2.5.8...5...3..5...2...1.7.4.9.4.9.6.7.1
34
+ .5..1..4.1.7...6.2...9.5...2.8.3.5.1.4..7..2.9.1.8.4.6...4.1...3.4...7.9.2..6..1.
35
+ .53...79...97534..1.......2.9..8..1....9.7....8..3..7.5.......3..76412...61...94.
36
+ ..6.8.3...49.7.25....4.5...6..317..4..7...8..1..826..9...7.2....75.4.19...3.9.6..
37
+ ..5.8.7..7..2.4..532.....84.6.1.5.4...8...5...7.8.3.1.45.....916..5.8..7..3.1.6..
38
+ ...9..8..128..64...7.8...6.8..43...75.......96...79..8.9...4.1...36..284..1..7...
39
+ ....8....27.....54.95...81...98.64...2.4.3.6...69.51...17...62.46.....38....9....
40
+ ...6.2...4...5...1.85.1.62..382.671...........194.735..26.4.53.9...2...7...8.9...
41
+ ...9....2.5.1234...3....16.9.8.......7.....9.......2.5.91....5...7439.2.4....7...
42
+ 38..........4..785..9.2.3...6..9....8..3.2..9....4..7...1.7.5..495..6..........92
43
+ ...158.....2.6.8...3.....4..27.3.51...........46.8.79..5.....8...4.7.1.....325...
44
+ .1.5..2..9....1.....2..8.3.5...3...7..8...5..6...8...4.4.1..7.....7....6..3..4.5.
45
+ .8.....4....469...4.......7..59.46...7.6.8.3...85.21..9.......5...781....6.....1.
46
+ 9.42....7.1..........7.65.....8...9..2.9.4.6..4...2.....16.7..........3.3....57.2
47
+ ...7..8....6....31.4...2....24.7.....1..3..8.....6.29....8...7.86....5....2..6...
48
+ ..1..7.9.59..8...1.3.....8......58...5..6..2...41......8.....3.1...2..79.2.7..4..
49
+ .....3.17.15..9..8.6.......1....7.....9...2.....5....4.......2.5..6..34.34.2.....
50
+ 3..2........1.7...7.6.3.5...7...9.8.9...2...4.1.8...5...9.4.3.1...7.2........8..6
@@ -0,0 +1,11 @@
1
+ 85...24..72......9..4.........1.7..23.5...9...4...........8..7..17..........36.4.
2
+ ..53.....8......2..7..1.5..4....53...1..7...6..32...8..6.5....9..4....3......97..
3
+ 12..4......5.69.1...9...5.........7.7...52.9..3......2.9.6...5.4..9..8.1..3...9.4
4
+ ...57..3.1......2.7...234......8...4..7..4...49....6.5.42...3.....7..9....18.....
5
+ 7..1523........92....3.....1....47.8.......6............9...5.6.4.9.7...8....6.1.
6
+ 1....7.9..3..2...8..96..5....53..9...1..8...26....4...3......1..4......7..7...3..
7
+ 1...34.8....8..5....4.6..21.18......3..1.2..6......81.52..7.9....6..9....9.64...2
8
+ ...92......68.3...19..7...623..4.1....1...7....8.3..297...8..91...5.72......64...
9
+ .6.5.4.3.1...9...8.........9...5...6.4.6.2.7.7...4...5.........4...8...1.5.2.3.4.
10
+ 7.....4...2..7..8...3..8.799..5..3...6..2..9...1.97..6...3..9...3..4..6...9..1.35
11
+ ....7..2.8.......6.1.2.5...9.54....8.........3....85.1...3.2.8.4.......9.7..6....
@@ -0,0 +1,95 @@
1
+ 4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......
2
+ 52...6.........7.13...........4..8..6......5...........418.........3..2...87.....
3
+ 6.....8.3.4.7.................5.4.7.3..2.....1.6.......2.....5.....8.6......1....
4
+ 48.3............71.2.......7.5....6....2..8.............1.76...3.....4......5....
5
+ ....14....3....2...7..........9...3.6.1.............8.2.....1.4....5.6.....7.8...
6
+ ......52..8.4......3...9...5.1...6..2..7........3.....6...1..........7.4.......3.
7
+ 6.2.5.........3.4..........43...8....1....2........7..5..27...........81...6.....
8
+ .524.........7.1..............8.2...3.....6...9.5.....1.6.3...........897........
9
+ 6.2.5.........4.3..........43...8....1....2........7..5..27...........81...6.....
10
+ .923.........8.1...........1.7.4...........658.........6.5.2...4.....7.....9.....
11
+ 6..3.2....5.....1..........7.26............543.........8.15........4.2........7..
12
+ .6.5.1.9.1...9..539....7....4.8...7.......5.8.817.5.3.....5.2............76..8...
13
+ ..5...987.4..5...1..7......2...48....9.1.....6..2.....3..6..2.......9.7.......5..
14
+ 3.6.7...........518.........1.4.5...7.....6.....2......2.....4.....8.3.....5.....
15
+ 1.....3.8.7.4..............2.3.1...........958.........5.6...7.....8.2...4.......
16
+ 6..3.2....4.....1..........7.26............543.........8.15........4.2........7..
17
+ ....3..9....2....1.5.9..............1.2.8.4.6.8.5...2..75......4.1..6..3.....4.6.
18
+ 45.....3....8.1....9...........5..9.2..7.....8.........1..4..........7.2...6..8..
19
+ .237....68...6.59.9.....7......4.97.3.7.96..2.........5..47.........2....8.......
20
+ ..84...3....3.....9....157479...8........7..514.....2...9.6...2.5....4......9..56
21
+ .98.1....2......6.............3.2.5..84.........6.........4.8.93..5...........1..
22
+ ..247..58..............1.4.....2...9528.9.4....9...1.........3.3....75..685..2...
23
+ 4.....8.5.3..........7......2.....6.....5.4......1.......6.3.7.5..2.....1.9......
24
+ .2.3......63.....58.......15....9.3....7........1....8.879..26......6.7...6..7..4
25
+ 1.....7.9.4...72..8.........7..1..6.3.......5.6..4..2.........8..53...7.7.2....46
26
+ 4.....3.....8.2......7........1...8734.......6........5...6........1.4...82......
27
+ .......71.2.8........4.3...7...6..5....2..3..9........6...7.....8....4......5....
28
+ 6..3.2....4.....8..........7.26............543.........8.15........8.2........7..
29
+ .47.8...1............6..7..6....357......5....1..6....28..4.....9.1...4.....2.69.
30
+ ......8.17..2........5.6......7...5..1....3...8.......5......2..4..8....6...3....
31
+ 38.6.......9.......2..3.51......5....3..1..6....4......17.5..8.......9.......7.32
32
+ ...5...........5.697.....2...48.2...25.1...3..8..3.........4.7..13.5..9..2...31..
33
+ .2.......3.5.62..9.68...3...5..........64.8.2..47..9....3.....1.....6...17.43....
34
+ .8..4....3......1........2...5...4.69..1..8..2...........3.9....6....5.....2.....
35
+ ..8.9.1...6.5...2......6....3.1.7.5.........9..4...3...5....2...7...3.8.2..7....4
36
+ 4.....5.8.3..........7......2.....6.....5.8......1.......6.3.7.5..2.....1.8......
37
+ 1.....3.8.6.4..............2.3.1...........958.........5.6...7.....8.2...4.......
38
+ 1....6.8..64..........4...7....9.6...7.4..5..5...7.1...5....32.3....8...4........
39
+ 249.6...3.3....2..8.......5.....6......2......1..4.82..9.5..7....4.....1.7...3...
40
+ ...8....9.873...4.6..7.......85..97...........43..75.......3....3...145.4....2..1
41
+ ...5.1....9....8...6.......4.1..........7..9........3.8.....1.5...2..4.....36....
42
+ ......8.16..2........7.5......6...2..1....3...8.......2......7..3..8....5...4....
43
+ .476...5.8.3.....2.....9......8.5..6...1.....6.24......78...51...6....4..9...4..7
44
+ .....7.95.....1...86..2.....2..73..85......6...3..49..3.5...41724................
45
+ .4.5.....8...9..3..76.2.....146..........9..7.....36....1..4.5..6......3..71..2..
46
+ .834.........7..5...........4.1.8..........27...3.....2.6.5....5.....8........1..
47
+ ..9.....3.....9...7.....5.6..65..4.....3......28......3..75.6..6...........12.3.8
48
+ .26.39......6....19.....7.......4..9.5....2....85.....3..2..9..4....762.........4
49
+ 2.3.8....8..7...........1...6.5.7...4......3....1............82.5....6...1.......
50
+ 6..3.2....1.....5..........7.26............843.........8.15........8.2........7..
51
+ 1.....9...64..1.7..7..4.......3.....3.89..5....7....2.....6.7.9.....4.1....129.3.
52
+ .........9......84.623...5....6...453...1...6...9...7....1.....4.5..2....3.8....9
53
+ .2....5938..5..46.94..6...8..2.3.....6..8.73.7..2.........4.38..7....6..........5
54
+ 9.4..5...25.6..1..31......8.7...9...4..26......147....7.......2...3..8.6.4.....9.
55
+ ...52.....9...3..4......7...1.....4..8..453..6...1...87.2........8....32.4..8..1.
56
+ 53..2.9...24.3..5...9..........1.827...7.........981.............64....91.2.5.43.
57
+ 1....786...7..8.1.8..2....9........24...1......9..5...6.8..........5.9.......93.4
58
+ ....5...11......7..6.....8......4.....9.1.3.....596.2..8..62..7..7......3.5.7.2..
59
+ .47.2....8....1....3....9.2.....5...6..81..5.....4.....7....3.4...9...1.4..27.8..
60
+ ......94.....9...53....5.7..8.4..1..463...........7.8.8..7.....7......28.5.26....
61
+ .2......6....41.....78....1......7....37.....6..412....1..74..5..8.5..7......39..
62
+ 1.....3.8.6.4..............2.3.1...........758.........7.5...6.....8.2...4.......
63
+ 2....1.9..1..3.7..9..8...2.......85..6.4.........7...3.2.3...6....5.....1.9...2.5
64
+ ..7..8.....6.2.3...3......9.1..5..6.....1.....7.9....2........4.83..4...26....51.
65
+ ...36....85.......9.4..8........68.........17..9..45...1.5...6.4....9..2.....3...
66
+ 34.6.......7.......2..8.57......5....7..1..2....4......36.2..1.......9.......7.82
67
+ ......4.18..2........6.7......8...6..4....3...1.......6......2..5..1....7...3....
68
+ .4..5..67...1...4....2.....1..8..3........2...6...........4..5.3.....8..2........
69
+ .......4...2..4..1.7..5..9...3..7....4..6....6..1..8...2....1..85.9...6.....8...3
70
+ 8..7....4.5....6............3.97...8....43..5....2.9....6......2...6...7.71..83.2
71
+ .8...4.5....7..3............1..85...6.....2......4....3.26............417........
72
+ ....7..8...6...5...2...3.61.1...7..2..8..534.2..9.......2......58...6.3.4...1....
73
+ ......8.16..2........7.5......6...2..1....3...8.......2......7..4..8....5...3....
74
+ .2..........6....3.74.8.........3..2.8..4..1.6..5.........1.78.5....9..........4.
75
+ .52..68.......7.2.......6....48..9..2..41......1.....8..61..38.....9...63..6..1.9
76
+ ....1.78.5....9..........4..2..........6....3.74.8.........3..2.8..4..1.6..5.....
77
+ 1.......3.6.3..7...7...5..121.7...9...7........8.1..2....8.64....9.2..6....4.....
78
+ 4...7.1....19.46.5.....1......7....2..2.3....847..6....14...8.6.2....3..6...9....
79
+ ......8.17..2........5.6......7...5..1....3...8.......5......2..3..8....6...4....
80
+ 963......1....8......2.5....4.8......1....7......3..257......3...9.2.4.7......9..
81
+ 15.3......7..4.2....4.72.....8.........9..1.8.1..8.79......38...........6....7423
82
+ ..........5724...98....947...9..3...5..9..12...3.1.9...6....25....56.....7......6
83
+ ....75....1..2.....4...3...5.....3.2...8...1.......6.....1..48.2........7........
84
+ 6.....7.3.4.8.................5.4.8.7..2.....1.3.......2.....5.....7.9......1....
85
+ ....6...4..6.3....1..4..5.77.....8.5...8.....6.8....9...2.9....4....32....97..1..
86
+ .32.....58..3.....9.428...1...4...39...6...5.....1.....2...67.8.....4....95....6.
87
+ ...5.3.......6.7..5.8....1636..2.......4.1.......3...567....2.8..4.7.......2..5..
88
+ .5.3.7.4.1.........3.......5.8.3.61....8..5.9.6..1........4...6...6927....2...9..
89
+ ..5..8..18......9.......78....4.....64....9......53..2.6.........138..5....9.714.
90
+ ..........72.6.1....51...82.8...13..4.........37.9..1.....238..5.4..9.........79.
91
+ ...658.....4......12............96.7...3..5....2.8...3..19..8..3.6.....4....473..
92
+ .2.3.......6..8.9.83.5........2...8.7.9..5........6..4.......1...1...4.22..7..8.9
93
+ .5..9....1.....6.....3.8.....8.4...9514.......3....2..........4.8...6..77..15..6.
94
+ .....2.......7...17..3...9.8..7......2.89.6...13..6....9..5.824.....891..........
95
+ 3...8.......7....51..............36...2..4....7...........6.13..452...........8..
@@ -0,0 +1,85 @@
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 this
4
+ # file to always be loaded, without a need to explicitly require it in any files.
5
+ #
6
+ # Given that it is always loaded, you are encouraged to keep this file as
7
+ # light-weight as possible. Requiring heavyweight dependencies from this file
8
+ # will add to the boot time of your test suite on EVERY test run, even for an
9
+ # individual file that may not need all of that loaded. Instead, consider making
10
+ # a separate helper file that requires the additional dependencies and performs
11
+ # the additional setup, and require it from the spec files that actually need it.
12
+ #
13
+ # The `.rspec` file also contains a few flags that are not defaults but that
14
+ # users commonly want.
15
+ #
16
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
17
+ RSpec.configure do |config|
18
+ # rspec-expectations config goes here. You can use an alternate
19
+ # assertion/expectation library such as wrong or the stdlib/minitest
20
+ # assertions if you prefer.
21
+ config.expect_with :rspec do |expectations|
22
+ # This option will default to `true` in RSpec 4. It makes the `description`
23
+ # and `failure_message` of custom matchers include text for helper methods
24
+ # defined using `chain`, e.g.:
25
+ # be_bigger_than(2).and_smaller_than(4).description
26
+ # # => "be bigger than 2 and smaller than 4"
27
+ # ...rather than:
28
+ # # => "be bigger than 2"
29
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
30
+ end
31
+
32
+ # rspec-mocks config goes here. You can use an alternate test double
33
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
34
+ config.mock_with :rspec do |mocks|
35
+ # Prevents you from mocking or stubbing a method that does not exist on
36
+ # a real object. This is generally recommended, and will default to
37
+ # `true` in RSpec 4.
38
+ mocks.verify_partial_doubles = true
39
+ end
40
+
41
+ # These two settings work together to allow you to limit a spec run
42
+ # to individual examples or groups you care about by tagging them with
43
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
44
+ # get run.
45
+ config.filter_run :focus
46
+ config.run_all_when_everything_filtered = true
47
+
48
+ # Limits the available syntax to the non-monkey patched syntax that is recommended.
49
+ # For more details, see:
50
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
51
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
52
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
53
+ config.disable_monkey_patching!
54
+
55
+ # This setting enables warnings. It's recommended, but in some cases may
56
+ # be too noisy due to issues in dependencies.
57
+ config.warnings = true
58
+
59
+ # Many RSpec users commonly either run the entire suite or an individual
60
+ # file, and it's useful to allow more verbose output when running an
61
+ # individual spec file.
62
+ if config.files_to_run.one?
63
+ # Use the documentation formatter for detailed output,
64
+ # unless a formatter has already been configured
65
+ # (e.g. via a command-line flag).
66
+ config.default_formatter = 'doc'
67
+ end
68
+
69
+ # Print the 10 slowest examples and example groups at the
70
+ # end of the spec run, to help surface which specs are running
71
+ # particularly slow.
72
+ config.profile_examples = 10
73
+
74
+ # Run specs in random order to surface order dependencies. If you find an
75
+ # order dependency and want to debug it, you can fix the order by providing
76
+ # the seed, which is printed after each run.
77
+ # --seed 1234
78
+ config.order = :random
79
+
80
+ # Seed global randomization in this process using the `--seed` CLI option.
81
+ # Setting this allows you to use `--seed` to deterministically reproduce
82
+ # test failures related to randomization by passing the same `--seed` value
83
+ # as the one that triggered the failure.
84
+ Kernel.srand config.seed
85
+ end
@@ -0,0 +1,51 @@
1
+ require 'sudokusolver_ng'
2
+
3
+ RSpec.describe 'Driver spec' do
4
+ before(:all) do
5
+ @solver = SudokuSolverNg.new
6
+
7
+ @easy = File.read(File.expand_path("spec/boards/easy50.txt")).split("\n")
8
+ @top95 = File.read(File.expand_path("spec/boards/top95.txt")).split("\n")
9
+ @hard = File.read(File.expand_path("spec/boards/hardest.txt")).split("\n")
10
+ end
11
+
12
+ def multiple(puzzles)
13
+ puzzles.map{|puzzle| @solver.check_solution(@solver.string_solution(@solver.search(@solver.parse_grid(puzzle)))) }
14
+ end
15
+
16
+ it 'should give the developers of this gem the idea that it solves properly' do
17
+ puts "Easy puzzle (constraint satisfaction only): "
18
+ puts
19
+ @solver.print_grid(@solver.search(@solver.parse_grid(@easy.first)))
20
+ puts "Hard puzzle (constraint satisfaction + search): "
21
+ puts
22
+ @solver.print_grid(@solver.search(@solver.parse_grid(@hard.first)))
23
+ end
24
+
25
+ it 'should solve the board' do
26
+ puzzle = '4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......'
27
+ solution = @solver.string_solution(@solver.search(@solver.parse_grid(puzzle)))
28
+
29
+ expect(@solver.check_solution(solution)).to be true
30
+ end
31
+
32
+ it 'run with an empty puzzle' do
33
+ puzzle = '.................................................................................'
34
+ solution = @solver.string_solution(@solver.search(@solver.parse_grid(puzzle)))
35
+
36
+ expect(@solver.check_solution(solution)).to be true
37
+ end
38
+
39
+ it 'should solve all easy boards' do
40
+ expect( multiple(@easy).all?{|solved| solved == true} ).to be true
41
+ end
42
+
43
+ it 'should solve all top95 boards' do
44
+ expect( multiple(@top95).all?{|solved| solved == true} ).to be true
45
+ end
46
+
47
+ it 'should solve all hard boards' do
48
+ expect( multiple(@hard).all?{|solved| solved == true} ).to be true
49
+ end
50
+
51
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sudokusolver_ng'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "sudokusolver_ng"
8
+ spec.version = SudokuSolverNg::VERSION
9
+ spec.authors = ["Martin-Louis Bright", "Kasper Grubbe"]
10
+ spec.email = ["mlbright@gmail.com", "kaspergrubbe@gmail.com"]
11
+ spec.summary = %q{Commandline program and library for solving Sudoku puzzles}
12
+ spec.homepage = ""
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.6"
21
+ spec.add_development_dependency "rake", "~> 10.0"
22
+ spec.add_development_dependency "rspec", "~> 3.1"
23
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sudokusolver_ng
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Martin-Louis Bright
8
+ - Kasper Grubbe
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2016-01-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.6'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.6'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '10.0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '10.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '3.1'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '3.1'
56
+ description:
57
+ email:
58
+ - mlbright@gmail.com
59
+ - kaspergrubbe@gmail.com
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - ".gitignore"
65
+ - ".rspec"
66
+ - ".travis.yml"
67
+ - COPYING
68
+ - Gemfile
69
+ - LICENSE
70
+ - README.md
71
+ - Rakefile
72
+ - lib/sudokusolver_ng.rb
73
+ - spec/boards/easy50.txt
74
+ - spec/boards/hardest.txt
75
+ - spec/boards/top95.txt
76
+ - spec/spec_helper.rb
77
+ - spec/sudoku_spec.rb
78
+ - sudokusolver_ng.gemspec
79
+ homepage: ''
80
+ licenses:
81
+ - MIT
82
+ metadata: {}
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 2.4.8
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: Commandline program and library for solving Sudoku puzzles
103
+ test_files:
104
+ - spec/boards/easy50.txt
105
+ - spec/boards/hardest.txt
106
+ - spec/boards/top95.txt
107
+ - spec/spec_helper.rb
108
+ - spec/sudoku_spec.rb