doku 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +9 -7
- data/VERSION +1 -1
- data/lib/doku/dancing_links.rb +18 -18
- data/lib/doku/solver.rb +5 -4
- metadata +24 -24
data/README.rdoc
CHANGED
@@ -43,23 +43,23 @@ This gem is designed to solve Sudoku-like puzzles. For the purposes of this gem
|
|
43
43
|
|
44
44
|
For example, in Sudoku, the glyphs are the numbers 0 through 9, the squares are the squares of a 9x9 grid, and the groups consist of nine rows, nine columns, and nine 3x3 squares.
|
45
45
|
|
46
|
-
Every Sudoku-like puzzle can be reduced to an {exact cover problem}[http://en.wikipedia.org/wiki/Exact_cover]. From there
|
46
|
+
Every Sudoku-like puzzle can be reduced to an {exact cover problem}[http://en.wikipedia.org/wiki/Exact_cover]. From there it can be efficiently solved with the {Dancing Links}[http://arxiv.org/abs/cs/0011047] algorithm discovered by Donald Knuth. That is the main purpose of this gem.
|
47
47
|
|
48
48
|
== Classes and Modules Overview
|
49
49
|
|
50
|
-
The Doku::
|
50
|
+
The <b>Doku::DancingLinks</b> module contains several classes that comprise a general-purpose implementation of the Dancing Links algorithm. This module is included in the Doku gem for convenience, but it is not specifically for solving Sudoku-like puzzles; it can be applied to any exact cover problem.
|
51
51
|
|
52
|
-
The Puzzle class
|
52
|
+
The <b>Doku::Puzzle</b> class is an abstract class for working with Sudoku-like puzzles. It implements the concepts of groups, glyphs and squares. Each instance of this class represents a particular assignment of glyphs to squares; at its core, an instance is just a hash where the keys are squares and the values are glyphs. This class provides <code>[]</code> and <code>[]=</code> methods for reading and modifying instances of the puzzle, and it makes <code>dup</code> and <code>clone</code> work correctly. This class provides equality comparison and solution checking.
|
53
53
|
|
54
|
-
The Doku::
|
54
|
+
The Puzzle class includes the <b>Doku::SolvableWithDancingLinks</b> module which provides methods for solving puzzles using Doku::DancingLinks. The solutions returned are instances of Puzzle. This module is the glue that connects Doku::Puzzle to Doku::DancingLinks.
|
55
55
|
|
56
|
-
The
|
56
|
+
The <b>Doku::SquareOnGrid</b> module is useful for any Sudoku-like puzzle that can be drawn on a 2D grid. It implements the string representations of the puzzle by providing an <code>initialize</code> method that creates puzzles from strings and a <code>to_s</code> method that creates strings from puzzles. It also provides convenient <code>get</code> and <code>set</code> methods for reading and modifying instances of the puzzle using grid coordinates.
|
57
57
|
|
58
|
-
The Doku::
|
58
|
+
The classes <b>Doku::Sudoku</b>, <b>Doku::Hexadoku</b>, and <b>Doku::Hexamurai</b> all inherit from Doku::Puzzle and include Doku::SquareOnGrid. As a user of the gem, these are the classes you will probably interact with most of the time. Because of the framework set up by Doku::Puzzle and include Doku::SquareOnGrid, the definitions of these classes are short and the methods provided by each of them are rich and consistent with eachother.
|
59
59
|
|
60
60
|
== Detailed Documentation
|
61
61
|
|
62
|
-
For detailed documentation of every class, module, and method
|
62
|
+
For detailed documentation of every class, module, and method go to the {rubydoc.info page}[http://rubydoc.info/github/DavidEGrayson/doku/master/frames] and look for the Class List.
|
63
63
|
|
64
64
|
== Contributing
|
65
65
|
|
@@ -74,6 +74,8 @@ There are many directions this gem could go in. The direction will be determine
|
|
74
74
|
* More types of puzzles that are solvable (e.g. puzzles that have groups with fewer squares than the number of glyphs).
|
75
75
|
* Improve this page. Ideally the method names should be linkified on the {rubydoc.info page}[http://rubydoc.info/github/DavidEGrayson/doku/master], but I still want something presentable to be on the {github repository}[https://github.com/DavidEGrayson/doku]. Here's an example of a link that looks good on RubyDoc.info but not on github: {Doku::Sudoku Sudoku}. If either YARD or Github could be configured to use a different file on the front page, that would suffice!
|
76
76
|
|
77
|
+
To report bugs, use the {github issues page}[https://github.com/DavidEGrayson/doku/issues].
|
78
|
+
|
77
79
|
== Philosophy
|
78
80
|
|
79
81
|
This gem is meant to showcase beautiful Ruby code. Test-driven development was used at all times during the development of this gem. I have spent many hours reviewing the code, looking for ways to make it simpler, and refactoring it. Every class and public method is documented. Every method is short. There are no ugly hacks. All method names were chosen carefully. At every level, the power of the Ruby language is exploited to its fullest potential. --David Grayson
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0
|
1
|
+
1.1.0
|
data/lib/doku/dancing_links.rb
CHANGED
@@ -250,19 +250,29 @@ module Doku::DancingLinks
|
|
250
250
|
alias :nodes :nodes_rightward
|
251
251
|
|
252
252
|
# Removes a row from the {LinkMatrix} by covering every
|
253
|
-
# column that it touches.
|
253
|
+
# column that it touches.
|
254
|
+
def choose
|
255
|
+
nodes_rightward.each do |node|
|
256
|
+
node.column.cover
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
# Removes a row from the {LinkMatrix} by covering every
|
261
|
+
# column that it touches EXCEPT self.column, which is
|
262
|
+
# assumed to already be covered.
|
263
|
+
# This represents (tentatively)
|
254
264
|
# choosing the node's row to be in our exact cover.
|
255
265
|
# When that choice is proven to not work, this action can
|
256
|
-
# be efficiently undone with {#
|
257
|
-
def
|
266
|
+
# be efficiently undone with {#unchoose_except_self_column}.
|
267
|
+
def choose_except_self_column
|
258
268
|
nodes_except_self_rightward.each do |node|
|
259
269
|
node.column.cover
|
260
270
|
end
|
261
271
|
end
|
262
272
|
|
263
|
-
# Undoes the effect of {#
|
273
|
+
# Undoes the effect of {#choose_except_self_column}, putting
|
264
274
|
# the nodes of the row back into the {LinkMatrix}.
|
265
|
-
def
|
275
|
+
def unchoose_except_self_column
|
266
276
|
nodes_except_self_leftward.each do |node|
|
267
277
|
node.column.uncover
|
268
278
|
end
|
@@ -366,7 +376,7 @@ module Doku::DancingLinks
|
|
366
376
|
# as a new column.
|
367
377
|
#
|
368
378
|
# @param column_ids (Enumerable) The column_ids that are in this row.
|
369
|
-
# @param row_id (Object) The id of this row. This is used to express express exact covers
|
379
|
+
# @param row_id (Object) The id of this row. This is used to express express exact covers.
|
370
380
|
def add_row(column_ids, row_id=column_ids.dup)
|
371
381
|
first_node = nil
|
372
382
|
column_ids = column_ids.uniq if column_ids.respond_to?(:uniq)
|
@@ -390,16 +400,6 @@ module Doku::DancingLinks
|
|
390
400
|
end
|
391
401
|
end
|
392
402
|
|
393
|
-
# Removes a row from the matrix.
|
394
|
-
# @param row_id (Object) The ID of the row that was specified when
|
395
|
-
# {#add_row} was called.
|
396
|
-
def remove_row(row_id)
|
397
|
-
raise ArgumentError, "Row with id #{row_id} not found." if !@rows[row_id]
|
398
|
-
@rows[row_id].nodes_rightward.each do |node|
|
399
|
-
node.column.cover
|
400
|
-
end
|
401
|
-
end
|
402
|
-
|
403
403
|
# Retrieves a node in the row with the specified ID or returns nil if there is
|
404
404
|
# no row with that ID.
|
405
405
|
# @param id (Object) The ID of the row that was specified when
|
@@ -493,7 +493,7 @@ module Doku::DancingLinks
|
|
493
493
|
|
494
494
|
# Try the node (push it and cover its columns).
|
495
495
|
nodes.push node
|
496
|
-
node.
|
496
|
+
node.choose_except_self_column
|
497
497
|
|
498
498
|
end
|
499
499
|
end
|
@@ -538,7 +538,7 @@ module Doku::DancingLinks
|
|
538
538
|
# We tried nodes.last and it didn't work, so
|
539
539
|
# pop it off and uncover the corresponding columns.
|
540
540
|
node = nodes.pop
|
541
|
-
node.
|
541
|
+
node.unchoose_except_self_column
|
542
542
|
|
543
543
|
# Try the next node in this column.
|
544
544
|
x = node.down
|
data/lib/doku/solver.rb
CHANGED
@@ -38,13 +38,14 @@ module Doku
|
|
38
38
|
# @return (DancingLinks::LinkMatrix)
|
39
39
|
def to_link_matrix
|
40
40
|
# Create the link matrix. This is a generic matrix
|
41
|
-
# that does not take in to account
|
41
|
+
# that does not take in to account the state of this instance.
|
42
42
|
sm = DancingLinks::LinkMatrix.from_sets sets_for_exact_cover_problem
|
43
43
|
|
44
|
-
# Take into account
|
45
|
-
#
|
44
|
+
# Take into account the state of this instance
|
45
|
+
# by "choosing" rows. This removes them from the matrix
|
46
|
+
# by covering all the columns they touch.
|
46
47
|
each do |square, glyph|
|
47
|
-
sm.
|
48
|
+
sm.row(SquareAndGlyph.new(square,glyph)).choose
|
48
49
|
end
|
49
50
|
|
50
51
|
sm
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: doku
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-02-
|
12
|
+
date: 2012-02-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: backports
|
16
|
-
requirement: &
|
16
|
+
requirement: &23796760 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *23796760
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rspec
|
27
|
-
requirement: &
|
27
|
+
requirement: &23796140 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *23796140
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: bundler
|
38
|
-
requirement: &
|
38
|
+
requirement: &23795460 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *23795460
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: jeweler
|
49
|
-
requirement: &
|
49
|
+
requirement: &23811100 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 1.6.2
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *23811100
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: rcov
|
60
|
-
requirement: &
|
60
|
+
requirement: &23810380 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *23810380
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: yard
|
71
|
-
requirement: &
|
71
|
+
requirement: &23809620 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *23809620
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: watchr
|
82
|
-
requirement: &
|
82
|
+
requirement: &23808740 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *23808740
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: ruby-prof
|
93
|
-
requirement: &
|
93
|
+
requirement: &23805220 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *23805220
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: linecache19
|
104
|
-
requirement: &
|
104
|
+
requirement: &23812680 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,10 +109,10 @@ dependencies:
|
|
109
109
|
version: '0'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *23812680
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: ruby-debug-base19
|
115
|
-
requirement: &
|
115
|
+
requirement: &23852140 !ruby/object:Gem::Requirement
|
116
116
|
none: false
|
117
117
|
requirements:
|
118
118
|
- - ! '>='
|
@@ -120,10 +120,10 @@ dependencies:
|
|
120
120
|
version: 0.11.26
|
121
121
|
type: :development
|
122
122
|
prerelease: false
|
123
|
-
version_requirements: *
|
123
|
+
version_requirements: *23852140
|
124
124
|
- !ruby/object:Gem::Dependency
|
125
125
|
name: ruby-debug19
|
126
|
-
requirement: &
|
126
|
+
requirement: &23851580 !ruby/object:Gem::Requirement
|
127
127
|
none: false
|
128
128
|
requirements:
|
129
129
|
- - ! '>='
|
@@ -131,7 +131,7 @@ dependencies:
|
|
131
131
|
version: '0'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
|
-
version_requirements: *
|
134
|
+
version_requirements: *23851580
|
135
135
|
description: ! 'This gem allows you to represent Sudoku-like puzzles
|
136
136
|
|
137
137
|
(Sudoku, Hexadoku, and Hexamurai) as objects and find
|