combinatorial_puzzle_solver 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +10 -0
- data/Gemfile +4 -0
- data/README.md +465 -0
- data/Rakefile +40 -0
- data/bin/setup +7 -0
- data/combinatorial_puzzle_solver.gemspec +28 -0
- data/example_puzzles/4x4 +1 -0
- data/example_puzzles/compile_examples.rb +116 -0
- data/example_puzzles/examples.yaml +243 -0
- data/example_puzzles/hard +11 -0
- data/example_puzzles/medium +12 -0
- data/example_puzzles/simple +9 -0
- data/exe/solve_sudoku +110 -0
- data/lib/combinatorial_puzzle_solver.rb +12 -0
- data/lib/combinatorial_puzzle_solver/constraint.rb +54 -0
- data/lib/combinatorial_puzzle_solver/identifier.rb +55 -0
- data/lib/combinatorial_puzzle_solver/inconsistency.rb +9 -0
- data/lib/combinatorial_puzzle_solver/possibilities.rb +89 -0
- data/lib/combinatorial_puzzle_solver/puzzle.rb +124 -0
- data/lib/combinatorial_puzzle_solver/solution_space.rb +159 -0
- data/lib/combinatorial_puzzle_solver/sudoku.rb +95 -0
- data/lib/combinatorial_puzzle_solver/version.rb +4 -0
- metadata +155 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,465 @@
|
|
1
|
+
# Combinatorial Puzzle Solver
|
2
|
+
|
3
|
+
A resolver of combinatorial number-placement puzzles, like Sudoku.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'combinatorial_puzzle_solver'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install combinatorial_puzzle_solver
|
20
|
+
|
21
|
+
## Usage for `solve_sudoku`
|
22
|
+
|
23
|
+
The program `solve_sudoku` reads sudoku puzzles from files (or stdin, if no filenames is given) and solves them by constraint resolution. If constraint resolution is not enough to solve the puzzle, it will resort to a trial and error approach. The exit code will indicate if all parsed puzzles was completely solved or not.
|
24
|
+
Each resolution step and the current state of the puzzle can be written to stdout for diagnostic purposes. It is also possible to abort after a given number of steps if a complete resolution is not desired, which would be the case if you only want a couple of clues.
|
25
|
+
Note that the step output and abort functionality is not available when the puzzle is solved by trial and error.
|
26
|
+
The default behavior is resolve all given puzzles (with trial and error, if neccessary) and indicate by exit status whether all puzzles where completely resolved. No output is given unless explicitly asked for.
|
27
|
+
|
28
|
+
|
29
|
+
###Printing the parsed puzzles, `-i`.
|
30
|
+
|
31
|
+
The parser will interpret digits (0-9) as values in the puzzle and disregard anything else. The option `-i` will output the parsed puzzle before it solves it.
|
32
|
+
|
33
|
+
Given the file `example_puzzles/simple`:
|
34
|
+
|
35
|
+
906813540
|
36
|
+
201045063
|
37
|
+
040000000
|
38
|
+
000620009
|
39
|
+
009000200
|
40
|
+
700034000
|
41
|
+
000000090
|
42
|
+
590360104
|
43
|
+
027459306
|
44
|
+
|
45
|
+
|
46
|
+
Invoking `./solve_sudoku example_puzzles/simple -i` will return exit code `0` and output:
|
47
|
+
|
48
|
+
9 6|8 1 3|5 4
|
49
|
+
2 1| 4 5| 6 3
|
50
|
+
4 | |
|
51
|
+
-----+-----+-----
|
52
|
+
|6 2 | 9
|
53
|
+
9| |2
|
54
|
+
7 | 3 4|
|
55
|
+
-----+-----+-----
|
56
|
+
| | 9
|
57
|
+
5 9 |3 6 |1 4
|
58
|
+
2 7|4 5 9|3 6
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
|
63
|
+
###Parsing several puzzles at the same time
|
64
|
+
|
65
|
+
Given the file `example_puzzles/simple`:
|
66
|
+
|
67
|
+
906813540
|
68
|
+
201045063
|
69
|
+
040000000
|
70
|
+
000620009
|
71
|
+
009000200
|
72
|
+
700034000
|
73
|
+
000000090
|
74
|
+
590360104
|
75
|
+
027459306
|
76
|
+
|
77
|
+
|
78
|
+
Given the file `example_puzzles/medium`:
|
79
|
+
|
80
|
+
000|301|000
|
81
|
+
009|000|000
|
82
|
+
080|000|030
|
83
|
+
---+---+---
|
84
|
+
000|004|980
|
85
|
+
007|120|500
|
86
|
+
200|090|170
|
87
|
+
---+---+---
|
88
|
+
050|012|000
|
89
|
+
090|007|000
|
90
|
+
300|405|008
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
Invoking `./solve_sudoku example_puzzles/simple example_puzzles/medium -i` will return exit code `0` and output:
|
95
|
+
|
96
|
+
9 6|8 1 3|5 4
|
97
|
+
2 1| 4 5| 6 3
|
98
|
+
4 | |
|
99
|
+
-----+-----+-----
|
100
|
+
|6 2 | 9
|
101
|
+
9| |2
|
102
|
+
7 | 3 4|
|
103
|
+
-----+-----+-----
|
104
|
+
| | 9
|
105
|
+
5 9 |3 6 |1 4
|
106
|
+
2 7|4 5 9|3 6
|
107
|
+
|
108
|
+
|3 1|
|
109
|
+
9| |
|
110
|
+
8 | | 3
|
111
|
+
-----+-----+-----
|
112
|
+
| 4|9 8
|
113
|
+
7|1 2 |5
|
114
|
+
2 | 9 |1 7
|
115
|
+
-----+-----+-----
|
116
|
+
5 | 1 2|
|
117
|
+
9 | 7|
|
118
|
+
3 |4 5| 8
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
###Parsing 4x4 puzzles, `-4`, `-4x4`.
|
124
|
+
|
125
|
+
Given the file `example_puzzles/4x4`:
|
126
|
+
|
127
|
+
this is a tiny puzzle 0040100000030100
|
128
|
+
|
129
|
+
|
130
|
+
Invoking `./solve_sudoku example_puzzles/4x4 -i -4` will return exit code `0` and output:
|
131
|
+
|
132
|
+
|4
|
133
|
+
1 |
|
134
|
+
---+---
|
135
|
+
| 3
|
136
|
+
1|
|
137
|
+
|
138
|
+
|
139
|
+
|
140
|
+
|
141
|
+
###Printing the output, `-o`.
|
142
|
+
|
143
|
+
Given the file `example_puzzles/simple`:
|
144
|
+
|
145
|
+
906813540
|
146
|
+
201045063
|
147
|
+
040000000
|
148
|
+
000620009
|
149
|
+
009000200
|
150
|
+
700034000
|
151
|
+
000000090
|
152
|
+
590360104
|
153
|
+
027459306
|
154
|
+
|
155
|
+
|
156
|
+
Invoking `./solve_sudoku example_puzzles/simple -o` will return exit code `0` and output:
|
157
|
+
|
158
|
+
9 7 6|8 1 3|5 4 2
|
159
|
+
2 8 1|7 4 5|9 6 3
|
160
|
+
3 4 5|2 9 6|8 1 7
|
161
|
+
-----+-----+-----
|
162
|
+
8 5 3|6 2 1|4 7 9
|
163
|
+
4 6 9|5 7 8|2 3 1
|
164
|
+
7 1 2|9 3 4|6 5 8
|
165
|
+
-----+-----+-----
|
166
|
+
6 3 4|1 8 2|7 9 5
|
167
|
+
5 9 8|3 6 7|1 2 4
|
168
|
+
1 2 7|4 5 9|3 8 6
|
169
|
+
|
170
|
+
|
171
|
+
|
172
|
+
|
173
|
+
###Printing the resolution steps, `-s`.
|
174
|
+
|
175
|
+
Given the file `example_puzzles/simple`:
|
176
|
+
|
177
|
+
906813540
|
178
|
+
201045063
|
179
|
+
040000000
|
180
|
+
000620009
|
181
|
+
009000200
|
182
|
+
700034000
|
183
|
+
000000090
|
184
|
+
590360104
|
185
|
+
027459306
|
186
|
+
|
187
|
+
|
188
|
+
Invoking `./solve_sudoku example_puzzles/simple -o -s` will return exit code `0` and output:
|
189
|
+
|
190
|
+
[1,2]=7
|
191
|
+
[8,3]=8
|
192
|
+
[9,8]=8
|
193
|
+
[1,9]=2
|
194
|
+
[2,2]=8
|
195
|
+
[9,1]=1
|
196
|
+
[7,7]=7
|
197
|
+
[3,1]=3
|
198
|
+
[7,5]=8
|
199
|
+
[7,9]=5
|
200
|
+
[2,7]=9
|
201
|
+
[8,8]=2
|
202
|
+
[3,3]=5
|
203
|
+
[5,5]=7
|
204
|
+
[2,4]=7
|
205
|
+
[3,7]=8
|
206
|
+
[8,6]=7
|
207
|
+
[6,3]=2
|
208
|
+
[3,5]=9
|
209
|
+
[4,7]=4
|
210
|
+
[6,7]=6
|
211
|
+
[3,4]=2
|
212
|
+
[4,1]=8
|
213
|
+
[4,3]=3
|
214
|
+
[3,6]=6
|
215
|
+
[7,4]=1
|
216
|
+
[4,6]=1
|
217
|
+
[7,3]=4
|
218
|
+
[7,6]=2
|
219
|
+
[5,4]=5
|
220
|
+
[4,2]=5
|
221
|
+
[5,6]=8
|
222
|
+
[7,1]=6
|
223
|
+
[6,4]=9
|
224
|
+
[4,8]=7
|
225
|
+
[6,2]=1
|
226
|
+
[5,9]=1
|
227
|
+
[7,2]=3
|
228
|
+
[5,1]=4
|
229
|
+
[3,8]=1
|
230
|
+
[6,8]=5
|
231
|
+
[6,9]=8
|
232
|
+
[5,2]=6
|
233
|
+
[5,8]=3
|
234
|
+
[3,9]=7
|
235
|
+
9 7 6|8 1 3|5 4 2
|
236
|
+
2 8 1|7 4 5|9 6 3
|
237
|
+
3 4 5|2 9 6|8 1 7
|
238
|
+
-----+-----+-----
|
239
|
+
8 5 3|6 2 1|4 7 9
|
240
|
+
4 6 9|5 7 8|2 3 1
|
241
|
+
7 1 2|9 3 4|6 5 8
|
242
|
+
-----+-----+-----
|
243
|
+
6 3 4|1 8 2|7 9 5
|
244
|
+
5 9 8|3 6 7|1 2 4
|
245
|
+
1 2 7|4 5 9|3 8 6
|
246
|
+
|
247
|
+
|
248
|
+
|
249
|
+
|
250
|
+
###Printing the entire puzzle for each resolution step, `-p`.
|
251
|
+
|
252
|
+
Given the file `example_puzzles/4x4`:
|
253
|
+
|
254
|
+
this is a tiny puzzle 0040100000030100
|
255
|
+
|
256
|
+
|
257
|
+
Invoking `./solve_sudoku example_puzzles/4x4 --4x4 -p` will return exit code `0` and output:
|
258
|
+
|
259
|
+
|4
|
260
|
+
1 | 2
|
261
|
+
---+---
|
262
|
+
| 3
|
263
|
+
1|
|
264
|
+
|
265
|
+
|4
|
266
|
+
1 | 2
|
267
|
+
---+---
|
268
|
+
| 3
|
269
|
+
1|2
|
270
|
+
|
271
|
+
|4
|
272
|
+
1 |3 2
|
273
|
+
---+---
|
274
|
+
| 3
|
275
|
+
1|2
|
276
|
+
|
277
|
+
|4 1
|
278
|
+
1 |3 2
|
279
|
+
---+---
|
280
|
+
| 3
|
281
|
+
1|2
|
282
|
+
|
283
|
+
|4 1
|
284
|
+
1 |3 2
|
285
|
+
---+---
|
286
|
+
| 3
|
287
|
+
1|2 4
|
288
|
+
|
289
|
+
|4 1
|
290
|
+
1 |3 2
|
291
|
+
---+---
|
292
|
+
|1 3
|
293
|
+
1|2 4
|
294
|
+
|
295
|
+
|4 1
|
296
|
+
1 4|3 2
|
297
|
+
---+---
|
298
|
+
|1 3
|
299
|
+
1|2 4
|
300
|
+
|
301
|
+
|4 1
|
302
|
+
1 4|3 2
|
303
|
+
---+---
|
304
|
+
|1 3
|
305
|
+
3 1|2 4
|
306
|
+
|
307
|
+
|4 1
|
308
|
+
1 4|3 2
|
309
|
+
---+---
|
310
|
+
2|1 3
|
311
|
+
3 1|2 4
|
312
|
+
|
313
|
+
2 |4 1
|
314
|
+
1 4|3 2
|
315
|
+
---+---
|
316
|
+
2|1 3
|
317
|
+
3 1|2 4
|
318
|
+
|
319
|
+
2 |4 1
|
320
|
+
1 4|3 2
|
321
|
+
---+---
|
322
|
+
4 2|1 3
|
323
|
+
3 1|2 4
|
324
|
+
|
325
|
+
2 3|4 1
|
326
|
+
1 4|3 2
|
327
|
+
---+---
|
328
|
+
4 2|1 3
|
329
|
+
3 1|2 4
|
330
|
+
|
331
|
+
|
332
|
+
|
333
|
+
|
334
|
+
###Use constraint resolution only, `-r`.
|
335
|
+
|
336
|
+
You can avoid the trial and error functionality. Note though that this might not lead to a completely solved puzzle, which would imply a failure return code.
|
337
|
+
The input and incomplete result is demonstrated below.
|
338
|
+
|
339
|
+
Given the file `example_puzzles/medium`:
|
340
|
+
|
341
|
+
000|301|000
|
342
|
+
009|000|000
|
343
|
+
080|000|030
|
344
|
+
---+---+---
|
345
|
+
000|004|980
|
346
|
+
007|120|500
|
347
|
+
200|090|170
|
348
|
+
---+---+---
|
349
|
+
050|012|000
|
350
|
+
090|007|000
|
351
|
+
300|405|008
|
352
|
+
|
353
|
+
|
354
|
+
|
355
|
+
Invoking `./solve_sudoku example_puzzles/medium -i -o -r` will return exit code `256` and output:
|
356
|
+
|
357
|
+
|3 1|
|
358
|
+
9| |
|
359
|
+
8 | | 3
|
360
|
+
-----+-----+-----
|
361
|
+
| 4|9 8
|
362
|
+
7|1 2 |5
|
363
|
+
2 | 9 |1 7
|
364
|
+
-----+-----+-----
|
365
|
+
5 | 1 2|
|
366
|
+
9 | 7|
|
367
|
+
3 |4 5| 8
|
368
|
+
|
369
|
+
2 |3 8 1| 5 9
|
370
|
+
3 9|7 5 6|8 2
|
371
|
+
8 5|2 4 9| 3
|
372
|
+
-----+-----+-----
|
373
|
+
5 1 3|6 7 4|9 8 2
|
374
|
+
9 7|1 2 8|5 3
|
375
|
+
2 8|5 9 3|1 7
|
376
|
+
-----+-----+-----
|
377
|
+
8 5 |9 1 2|3 7
|
378
|
+
9 2|8 3 7| 1 5
|
379
|
+
3 7 1|4 6 5|2 9 8
|
380
|
+
|
381
|
+
|
382
|
+
|
383
|
+
|
384
|
+
Given the file `example_puzzles/hard`:
|
385
|
+
|
386
|
+
000|200|063
|
387
|
+
300|005|401
|
388
|
+
001|003|980
|
389
|
+
---+---+---
|
390
|
+
000|000|090
|
391
|
+
000|538|000
|
392
|
+
030|000|000
|
393
|
+
---+---+---
|
394
|
+
026|300|500
|
395
|
+
503|700|008
|
396
|
+
470|001|000
|
397
|
+
|
398
|
+
|
399
|
+
Invoking `./solve_sudoku example_puzzles/hard -i -o -r` will return exit code `256` and output:
|
400
|
+
|
401
|
+
|2 | 6 3
|
402
|
+
3 | 5|4 1
|
403
|
+
1| 3|9 8
|
404
|
+
-----+-----+-----
|
405
|
+
| | 9
|
406
|
+
|5 3 8|
|
407
|
+
3 | |
|
408
|
+
-----+-----+-----
|
409
|
+
2 6|3 |5
|
410
|
+
5 3|7 | 8
|
411
|
+
4 7 | 1|
|
412
|
+
|
413
|
+
|2 1 |7 6 3
|
414
|
+
3 7| 5|4 2 1
|
415
|
+
2 1| 7 3|9 8 5
|
416
|
+
-----+-----+-----
|
417
|
+
| |3 9
|
418
|
+
|5 3 8|
|
419
|
+
3 | |8 5
|
420
|
+
-----+-----+-----
|
421
|
+
2 6|3 |5
|
422
|
+
5 3|7 | 8
|
423
|
+
4 7 | 5 1| 3
|
424
|
+
|
425
|
+
|
426
|
+
|
427
|
+
|
428
|
+
###Abort after a given number of steps, `-c NUM`, `--clues NUM`.
|
429
|
+
|
430
|
+
If you don't want the entire puzzle solved, but just a couple of clues on how to get forward, you can abort the resolution with `-c`, and print each step with `-s`.
|
431
|
+
|
432
|
+
Given the file `example_puzzles/simple`:
|
433
|
+
|
434
|
+
906813540
|
435
|
+
201045063
|
436
|
+
040000000
|
437
|
+
000620009
|
438
|
+
009000200
|
439
|
+
700034000
|
440
|
+
000000090
|
441
|
+
590360104
|
442
|
+
027459306
|
443
|
+
|
444
|
+
|
445
|
+
Invoking `./solve_sudoku example_puzzles/simple -s -c 3` will return exit code `0` and output:
|
446
|
+
|
447
|
+
[1,2]=7
|
448
|
+
[8,3]=8
|
449
|
+
[9,8]=8
|
450
|
+
|
451
|
+
|
452
|
+
|
453
|
+
## Development
|
454
|
+
|
455
|
+
After checking out the repo, run `bin/setup` to install dependencies.
|
456
|
+
|
457
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
458
|
+
|
459
|
+
## Contributing
|
460
|
+
|
461
|
+
1. Fork it ( https://github.com/ErikSchlyter/combinatorial_puzzle_solver/fork )
|
462
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
463
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
464
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
465
|
+
5. Create a new Pull Request
|