sudoku_bardi 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/LICENSE.md +20 -0
- data/README.md +80 -0
- data/lib/sudoku_bardi.rb +272 -0
- data/spec/sudoku_bardi_spec.rb +18 -0
- data/spec/support/no_should_rspec.rb +9 -0
- data/spec/support/sudoku_bardi_test.rb +19 -0
- data/spec/support/sudoku_fixture.rb +76 -0
- data/sudoku_bardi.gemspec +27 -0
- metadata +72 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2013 Bardi Einarsson
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
sudoku\_bardi
|
2
|
+
=============
|
3
|
+
|
4
|
+
## Summary
|
5
|
+
|
6
|
+
Sudoku solver, validator and generator
|
7
|
+
|
8
|
+
## Description
|
9
|
+
|
10
|
+
sudoku\_bardi (see websudoku.com) is a set of tools for solving, validating and generating Sudoku puzzles.
|
11
|
+
|
12
|
+
## Why should one the sudoku\_bardi tools?
|
13
|
+
|
14
|
+
The Sudoku solution algorithm does not use recursion -- runs in limited memory and can find all solutions of incorrect puzzles.
|
15
|
+
|
16
|
+
## Version
|
17
|
+
|
18
|
+
v0.1.0 with comprehensive tests, was developed using ruby 1.9.3 and rspec 2.13.0. It does not have any specific Sudoku puzzle generators yet; however it provides a good foundation for any generator as it provides validation of solution uniqueness and shows the operations used in the puzzle solution(s).
|
19
|
+
|
20
|
+
## Installation
|
21
|
+
|
22
|
+
Get the v0.1.0 gem or clone the repository.
|
23
|
+
|
24
|
+
## Usage and documentation
|
25
|
+
|
26
|
+
Study the programs in the spec/ directory. See below for more information.
|
27
|
+
|
28
|
+
Try the software in irb:
|
29
|
+
|
30
|
+
irb prompt> load 'lib/sudoku_bardi.rb'
|
31
|
+
irb prompt> load 'spec/support/sudoku_fixture.rb'
|
32
|
+
irb prompt> include SudokuBardi
|
33
|
+
irb prompt> include SudokuFixture
|
34
|
+
irb prompt> s = Solver.new EXAMPLE2
|
35
|
+
irb prompt> s.take 1
|
36
|
+
|
37
|
+
After -- s.take 1 -- one will see a listing of an array of size 2. The 0 element is an array of operations made to get the solution. The 1 element is the solution.
|
38
|
+
|
39
|
+
[75, SudokuBardi::Five] means assign Five to square 75.
|
40
|
+
["start"] ends the operations to construct the puzzle.
|
41
|
+
["mark", 2, [SudokuBardi::Seven, SudokuBardi::Two], 1]
|
42
|
+
shows a backtrack mark for square 2. That type of thing
|
43
|
+
occurs when there is no longer any square with only one
|
44
|
+
possible value. The solver had to try Seven and Two to
|
45
|
+
get all possible solutions. The 1 points at Two as the
|
46
|
+
current value chosen.
|
47
|
+
|
48
|
+
0 1 2 3 4 5 6 7 8
|
49
|
+
9 10 11 12 13 14 15 16 17
|
50
|
+
18 19 20 21 22 23 24 25 26
|
51
|
+
27 28 29 30 31 32 33 34 35
|
52
|
+
36 37 38 39 40 41 42 43 44
|
53
|
+
45 46 47 48 49 50 51 52 53
|
54
|
+
54 55 56 57 58 59 60 61 62
|
55
|
+
63 64 65 66 67 68 69 70 71
|
56
|
+
72 73 74 75 76 77 78 79 80
|
57
|
+
|
58
|
+
## Requirements
|
59
|
+
|
60
|
+
Most likely any recent version of 1.9 ruby works.
|
61
|
+
|
62
|
+
## Test with rspec ~> 2.11, rspec -fd
|
63
|
+
|
64
|
+
Try the software in irb:
|
65
|
+
|
66
|
+
irb prompt> load 'spec/support/sudoku_bardi_test.rb'
|
67
|
+
irb prompt> load 'spec/support/sudoku_fixture.rb'
|
68
|
+
|
69
|
+
Note, to find the gem installation directory:
|
70
|
+
|
71
|
+
irb prompt> require 'sudoku_bardi'
|
72
|
+
irb prompt> $".grep(/sudoku_bardi/)[0]
|
73
|
+
irb prompt> Sudoku::Solver.new.method(:each).source_location
|
74
|
+
irb prompt> exit
|
75
|
+
|
76
|
+
## License
|
77
|
+
|
78
|
+
Copyright (c) 2013 Bardi Einarsson. Released under the MIT License. See the [LICENSE][license] file for further details.
|
79
|
+
|
80
|
+
[license]: https://github.com/bardibardi/sudoku_bardi/blob/master/LICENSE.md
|
data/lib/sudoku_bardi.rb
ADDED
@@ -0,0 +1,272 @@
|
|
1
|
+
module SudokuBardi
|
2
|
+
|
3
|
+
# row, column, box
|
4
|
+
RCB = [
|
5
|
+
[0,0,0],[0,1,0],[0,2,0],[0,3,1],[0,4,1],[0,5,1],[0,6,2],[0,7,2],[0,8,2],
|
6
|
+
[1,0,0],[1,1,0],[1,2,0],[1,3,1],[1,4,1],[1,5,1],[1,6,2],[1,7,2],[1,8,2],
|
7
|
+
[2,0,0],[2,1,0],[2,2,0],[2,3,1],[2,4,1],[2,5,1],[2,6,2],[2,7,2],[2,8,2],
|
8
|
+
[3,0,3],[3,1,3],[3,2,3],[3,3,4],[3,4,4],[3,5,4],[3,6,5],[3,7,5],[3,8,5],
|
9
|
+
[4,0,3],[4,1,3],[4,2,3],[4,3,4],[4,4,4],[4,5,4],[4,6,5],[4,7,5],[4,8,5],
|
10
|
+
[5,0,3],[5,1,3],[5,2,3],[5,3,4],[5,4,4],[5,5,4],[5,6,5],[5,7,5],[5,8,5],
|
11
|
+
[6,0,6],[6,1,6],[6,2,6],[6,3,7],[6,4,7],[6,5,7],[6,6,8],[6,7,8],[6,8,8],
|
12
|
+
[7,0,6],[7,1,6],[7,2,6],[7,3,7],[7,4,7],[7,5,7],[7,6,8],[7,7,8],[7,8,8],
|
13
|
+
[8,0,6],[8,1,6],[8,2,6],[8,3,7],[8,4,7],[8,5,7],[8,6,8],[8,7,8],[8,8,8]
|
14
|
+
]
|
15
|
+
|
16
|
+
class Piece; end
|
17
|
+
class One < Piece; end
|
18
|
+
class Two < Piece; end
|
19
|
+
class Three < Piece; end
|
20
|
+
class Four < Piece; end
|
21
|
+
class Five < Piece; end
|
22
|
+
class Six < Piece; end
|
23
|
+
class Seven < Piece; end
|
24
|
+
class Eight < Piece; end
|
25
|
+
class Nine < Piece; end
|
26
|
+
|
27
|
+
TO_S = { nil => '.',
|
28
|
+
One => '1', Two => '2', Three => '3',
|
29
|
+
Four => '4', Five => '5', Six => '6',
|
30
|
+
Seven => '7', Eight => '8', Nine => '9'
|
31
|
+
}
|
32
|
+
|
33
|
+
NINE = [One, Two, Three, Four, Five, Six, Seven, Eight, Nine]
|
34
|
+
|
35
|
+
class Solver
|
36
|
+
|
37
|
+
include Enumerable
|
38
|
+
|
39
|
+
def self.piece_from_char c
|
40
|
+
i = c.bytes.first - 49 # 49 == '0'.bytes.first + 1
|
41
|
+
return nil if 0 > i
|
42
|
+
NINE[i]
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.constraint c
|
46
|
+
a = []
|
47
|
+
c.size.times do
|
48
|
+
a << c.dup
|
49
|
+
end
|
50
|
+
a
|
51
|
+
end
|
52
|
+
|
53
|
+
def initialize board_str = ''
|
54
|
+
start
|
55
|
+
process board_str
|
56
|
+
push ['start']
|
57
|
+
end
|
58
|
+
|
59
|
+
def start
|
60
|
+
@board = [nil] * (NINE.size * NINE.size)
|
61
|
+
@rows = self.class.constraint NINE
|
62
|
+
@columns = self.class.constraint NINE
|
63
|
+
@boxes = self.class.constraint NINE
|
64
|
+
@ops = []
|
65
|
+
end
|
66
|
+
|
67
|
+
def board_to_s
|
68
|
+
a = @board.map do |piece|
|
69
|
+
TO_S[piece]
|
70
|
+
end
|
71
|
+
a.join ''
|
72
|
+
end
|
73
|
+
|
74
|
+
def possible i
|
75
|
+
r, c, b = RCB[i]
|
76
|
+
@rows[r] & @columns[c] & @boxes[b]
|
77
|
+
end
|
78
|
+
|
79
|
+
def do_op op
|
80
|
+
i, piece = op
|
81
|
+
r, c, b = RCB[i]
|
82
|
+
@rows[r] -= [piece]
|
83
|
+
@columns[c] -= [piece]
|
84
|
+
@boxes[b] -= [piece]
|
85
|
+
@board[i] = piece
|
86
|
+
op
|
87
|
+
end
|
88
|
+
|
89
|
+
def undo_op op
|
90
|
+
i, piece = op
|
91
|
+
r, c, b = RCB[i]
|
92
|
+
@rows[r] += [piece]
|
93
|
+
@columns[c] += [piece]
|
94
|
+
@boxes[b] += [piece]
|
95
|
+
@board[i] = nil
|
96
|
+
op
|
97
|
+
end
|
98
|
+
|
99
|
+
def pop_start
|
100
|
+
@ops.pop
|
101
|
+
end
|
102
|
+
|
103
|
+
def push_start
|
104
|
+
push ['start']
|
105
|
+
end
|
106
|
+
|
107
|
+
def pop
|
108
|
+
return nil if 'start' == @ops[-1][0]
|
109
|
+
@ops.pop
|
110
|
+
end
|
111
|
+
|
112
|
+
def push op
|
113
|
+
@ops << op
|
114
|
+
end
|
115
|
+
|
116
|
+
def process_str str_as_ops
|
117
|
+
ops = []
|
118
|
+
str_as_ops.each_char.with_index do |char, i|
|
119
|
+
piece = self.class.piece_from_char char
|
120
|
+
if piece
|
121
|
+
ps = possible i
|
122
|
+
raise "impossible #{char} at #{i}" unless ps.include? piece
|
123
|
+
push do_op([i, piece])
|
124
|
+
end
|
125
|
+
end
|
126
|
+
ops
|
127
|
+
end
|
128
|
+
|
129
|
+
def play ops
|
130
|
+
ops.each do |op|
|
131
|
+
push do_op(op)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def process board_str
|
136
|
+
play process_str(board_str)
|
137
|
+
end
|
138
|
+
|
139
|
+
def single i
|
140
|
+
processed_single = false
|
141
|
+
backtrack = false
|
142
|
+
ps = possible i
|
143
|
+
if 0 == ps.length
|
144
|
+
backtrack = true
|
145
|
+
end
|
146
|
+
if 1 == ps.length
|
147
|
+
processed_single = true
|
148
|
+
push do_op([i, ps[0]])
|
149
|
+
end
|
150
|
+
[processed_single, backtrack]
|
151
|
+
end
|
152
|
+
|
153
|
+
def singles
|
154
|
+
had_singles = true
|
155
|
+
finished = true
|
156
|
+
while had_singles
|
157
|
+
finished = true
|
158
|
+
single_found = false
|
159
|
+
@board.each_with_index do |piece, i|
|
160
|
+
if !piece
|
161
|
+
finished = false
|
162
|
+
processed_single, backtrack = single i
|
163
|
+
single_found ||= processed_single
|
164
|
+
if backtrack
|
165
|
+
push ['backtrack', i]
|
166
|
+
return finished
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
had_singles = single_found
|
171
|
+
end
|
172
|
+
finished
|
173
|
+
end
|
174
|
+
|
175
|
+
def min_choices
|
176
|
+
j = nil
|
177
|
+
count = 10
|
178
|
+
@board.each_with_index do |piece, i|
|
179
|
+
if !piece
|
180
|
+
len = possible(i).size
|
181
|
+
if len < count
|
182
|
+
j = i
|
183
|
+
count = len
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
j
|
188
|
+
end
|
189
|
+
|
190
|
+
def gen_choices
|
191
|
+
a = []
|
192
|
+
@board.each_with_index do |piece, i|
|
193
|
+
if !piece
|
194
|
+
ps = possible(i)
|
195
|
+
if 1 < ps.size
|
196
|
+
a += ps.map {|e| [i, e]}
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
a
|
201
|
+
end
|
202
|
+
|
203
|
+
def add_mark i
|
204
|
+
push ['mark', i, possible(i), -1]
|
205
|
+
end
|
206
|
+
|
207
|
+
def try
|
208
|
+
mark = pop.dup
|
209
|
+
mark[3] += 1
|
210
|
+
piece = mark[2][mark[3]]
|
211
|
+
push mark
|
212
|
+
if piece
|
213
|
+
push do_op([mark[1], piece])
|
214
|
+
else
|
215
|
+
push ['backtrack', mark[1]]
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def do_backtrack
|
220
|
+
pop if 'mark' == @ops[-1][0]
|
221
|
+
op = pop
|
222
|
+
if op
|
223
|
+
while 'mark' != op[0]
|
224
|
+
undo_op op if op[0].kind_of? Numeric
|
225
|
+
op = pop
|
226
|
+
return @ops unless op
|
227
|
+
end
|
228
|
+
end
|
229
|
+
push op if op
|
230
|
+
end
|
231
|
+
|
232
|
+
def solve_one
|
233
|
+
solved = false
|
234
|
+
until solved
|
235
|
+
if 'backtrack' == @ops[-1][0]
|
236
|
+
pop
|
237
|
+
do_backtrack
|
238
|
+
if 'start' == @ops[-1][0]
|
239
|
+
return nil
|
240
|
+
end
|
241
|
+
try
|
242
|
+
else
|
243
|
+
solved = singles
|
244
|
+
if !solved
|
245
|
+
i = min_choices
|
246
|
+
add_mark i
|
247
|
+
try
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
[@ops, board_to_s]
|
252
|
+
end
|
253
|
+
|
254
|
+
def each
|
255
|
+
first = true
|
256
|
+
finished = false
|
257
|
+
until finished
|
258
|
+
push ['backtrack', 81] unless first
|
259
|
+
first = false
|
260
|
+
result = solve_one
|
261
|
+
if result
|
262
|
+
yield [result[0].dup, result[1]]
|
263
|
+
else
|
264
|
+
finished = true
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
end # Solver
|
270
|
+
|
271
|
+
end # SudokuBardi
|
272
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'support/no_should_rspec'
|
2
|
+
require 'support/sudoku_bardi_test'
|
3
|
+
require 'support/sudoku_fixture'
|
4
|
+
include SudokuFixture
|
5
|
+
|
6
|
+
describe SudokuBardi::Solver do
|
7
|
+
|
8
|
+
it "should solve puzzles with unique solutions" do
|
9
|
+
expect(SudokuBardi.unique_solution?(EXAMPLE, SOLUTION)).to be_true
|
10
|
+
expect(SudokuBardi.unique_solution?(EXAMPLE2, SOLUTION2)).to be_true
|
11
|
+
expect(SudokuBardi.unique_solution?(EXAMPLE3, SOLUTION3)).to be_true
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should solve puzzles with multiple solutions" do
|
15
|
+
expect(SudokuBardi.empty_puzzle_has_at_least_100_solutions?).to be_true
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative '../../lib/sudoku_bardi'
|
2
|
+
|
3
|
+
module SudokuBardi
|
4
|
+
|
5
|
+
def self.unique_solution? puzzle_board, solution_board
|
6
|
+
s = Solver.new puzzle_board
|
7
|
+
solutions = s.take 2
|
8
|
+
return nil unless 1 == solutions.size
|
9
|
+
solutions[0][1] == solution_board
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.empty_puzzle_has_at_least_100_solutions?
|
13
|
+
s = Solver.new
|
14
|
+
solutions = s.take 100
|
15
|
+
100 == solutions.size
|
16
|
+
end
|
17
|
+
|
18
|
+
end # SudokuBardi
|
19
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module SudokuFixture
|
2
|
+
|
3
|
+
EXAMPLE = %w(
|
4
|
+
...3...1.
|
5
|
+
8...167.2
|
6
|
+
1....93..
|
7
|
+
7.3...645
|
8
|
+
5.68.49.7
|
9
|
+
294...8.1
|
10
|
+
..17....8
|
11
|
+
3.792...4
|
12
|
+
.6...1...
|
13
|
+
).join ''
|
14
|
+
|
15
|
+
SOLUTION = %w(
|
16
|
+
672385419
|
17
|
+
839416752
|
18
|
+
145279386
|
19
|
+
783192645
|
20
|
+
516834927
|
21
|
+
294657831
|
22
|
+
421763598
|
23
|
+
357928164
|
24
|
+
968541273
|
25
|
+
).join ''
|
26
|
+
|
27
|
+
EXAMPLE2 = %w(
|
28
|
+
.....8..6
|
29
|
+
9.17.53.4
|
30
|
+
.....4.1.
|
31
|
+
1..94..5.
|
32
|
+
49..5..67
|
33
|
+
.2..71..3
|
34
|
+
.3.4.....
|
35
|
+
2.53.97.1
|
36
|
+
7..5.....
|
37
|
+
).join ''
|
38
|
+
|
39
|
+
SOLUTION2 = %w(
|
40
|
+
342198576
|
41
|
+
961725384
|
42
|
+
857634912
|
43
|
+
173946258
|
44
|
+
498253167
|
45
|
+
526871493
|
46
|
+
639417825
|
47
|
+
285369741
|
48
|
+
714582639
|
49
|
+
).join ''
|
50
|
+
|
51
|
+
EXAMPLE3 = %w(
|
52
|
+
68.35....
|
53
|
+
....1..2.
|
54
|
+
..7.6.9..
|
55
|
+
1........
|
56
|
+
3.5.9.1.2
|
57
|
+
........9
|
58
|
+
..3.2.8..
|
59
|
+
.6..7....
|
60
|
+
....45.31
|
61
|
+
).join ''
|
62
|
+
|
63
|
+
SOLUTION3 = %w(
|
64
|
+
689352417
|
65
|
+
534917628
|
66
|
+
217468953
|
67
|
+
192584376
|
68
|
+
345796182
|
69
|
+
876231549
|
70
|
+
753129864
|
71
|
+
461873295
|
72
|
+
928645731
|
73
|
+
).join ''
|
74
|
+
|
75
|
+
end
|
76
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'sudoku_bardi'
|
3
|
+
s.version = '0.1.0'
|
4
|
+
s.date = '2013-05-23'
|
5
|
+
s.summary = "Sudoku solver, validator and generator"
|
6
|
+
s.description = "sudoku_bardi (see websudoku.com) is a set of tools for solving, validating and generating Sudoku puzzles."
|
7
|
+
|
8
|
+
s.authors = ['Bardi Einarsson']
|
9
|
+
s.email = ['bardi@hotmail.com']
|
10
|
+
s.homepage = 'https://github.com/bardibardi/sudoku_bardi'
|
11
|
+
s.required_ruby_version = '>= 1.9.2'
|
12
|
+
s.add_development_dependency('rspec', '~> 2.11')
|
13
|
+
|
14
|
+
s.files = %w(
|
15
|
+
.gitignore
|
16
|
+
Gemfile
|
17
|
+
LICENSE.md
|
18
|
+
README.md
|
19
|
+
sudoku_bardi.gemspec
|
20
|
+
lib/sudoku_bardi.rb
|
21
|
+
spec/sudoku_bardi_spec.rb
|
22
|
+
spec/support/no_should_rspec.rb
|
23
|
+
spec/support/sudoku_bardi_test.rb
|
24
|
+
spec/support/sudoku_fixture.rb
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sudoku_bardi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Bardi Einarsson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-05-23 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2.11'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.11'
|
30
|
+
description: sudoku_bardi (see websudoku.com) is a set of tools for solving, validating
|
31
|
+
and generating Sudoku puzzles.
|
32
|
+
email:
|
33
|
+
- bardi@hotmail.com
|
34
|
+
executables: []
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
files:
|
38
|
+
- .gitignore
|
39
|
+
- Gemfile
|
40
|
+
- LICENSE.md
|
41
|
+
- README.md
|
42
|
+
- sudoku_bardi.gemspec
|
43
|
+
- lib/sudoku_bardi.rb
|
44
|
+
- spec/sudoku_bardi_spec.rb
|
45
|
+
- spec/support/no_should_rspec.rb
|
46
|
+
- spec/support/sudoku_bardi_test.rb
|
47
|
+
- spec/support/sudoku_fixture.rb
|
48
|
+
homepage: https://github.com/bardibardi/sudoku_bardi
|
49
|
+
licenses: []
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ! '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 1.9.2
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
requirements: []
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.8.25
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: Sudoku solver, validator and generator
|
72
|
+
test_files: []
|