line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
=head1 NAME |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
Games::Sudoku::General - Solve sudoku-like puzzles. |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 SYNOPSIS |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
$su = Games::Sudoku::General->new (); |
8
|
|
|
|
|
|
|
print $su->problem(<solution(); |
9
|
|
|
|
|
|
|
3 . . . . 8 . 2 . |
10
|
|
|
|
|
|
|
. . . . . 9 . . . |
11
|
|
|
|
|
|
|
. . 2 7 . 5 . . . |
12
|
|
|
|
|
|
|
2 4 . 5 . . 8 . . |
13
|
|
|
|
|
|
|
. 8 5 . 7 4 . . 6 |
14
|
|
|
|
|
|
|
. 3 . . . . 9 4 . |
15
|
|
|
|
|
|
|
1 . 4 . . . . 7 2 |
16
|
|
|
|
|
|
|
. . 6 9 . . . 5 . |
17
|
|
|
|
|
|
|
. 7 . 6 1 2 . . 9 |
18
|
|
|
|
|
|
|
eod |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 DESCRIPTION |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
This package solves puzzles that involve the allocation of symbols |
23
|
|
|
|
|
|
|
among a number of sets, such that no set contains more than one of |
24
|
|
|
|
|
|
|
any symbol. This class of problem includes the puzzles known as |
25
|
|
|
|
|
|
|
'Sudoku', 'Number Place', and 'Wasabi'. |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
Each Sudoku puzzle is considered to be made up of a number of cells, |
28
|
|
|
|
|
|
|
each of which is a member of one or more sets, and each of which may |
29
|
|
|
|
|
|
|
contain exactly one symbol. The contents of some of the cells are |
30
|
|
|
|
|
|
|
given, and the problem is to deduce the contents of the rest of the |
31
|
|
|
|
|
|
|
cells. |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
Although such puzzles as Sudoku are presented on a square grid, this |
34
|
|
|
|
|
|
|
package does not assume any particular geometry. Instead, the topology |
35
|
|
|
|
|
|
|
of the puzzle is defined by the user in terms of a list of the sets |
36
|
|
|
|
|
|
|
to which each cell belongs. Some topology generators are provided, but |
37
|
|
|
|
|
|
|
the user has the option of hand-specifying an arbitrary topology. |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
Even on the standard 9 x 9 Sudoku topology there are variants in which |
40
|
|
|
|
|
|
|
unspecified cells are constrained in various ways (odd/even, high/low). |
41
|
|
|
|
|
|
|
Such variants are accommodated by defining named sets of allowed |
42
|
|
|
|
|
|
|
symbols, and then giving the set name for each unoccupied cell to which |
43
|
|
|
|
|
|
|
it applies. See the C attribute for more |
44
|
|
|
|
|
|
|
information and an example. |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
This module is able not only to solve a variety of Sudoku-like |
47
|
|
|
|
|
|
|
puzzles, but to 'explain' how it arrived at its solution. The |
48
|
|
|
|
|
|
|
steps() method, called after a solution is generated, lists in order |
49
|
|
|
|
|
|
|
what solution constraints were applied, what cell each constraint |
50
|
|
|
|
|
|
|
is applied to, and what symbol the cell was constrained to. |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
Test script t/sudoku.t demonstrates these features. ActivePerl users |
53
|
|
|
|
|
|
|
will have to download the kit from L or |
54
|
|
|
|
|
|
|
L to get this |
55
|
|
|
|
|
|
|
file. |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=head2 Exported symbols |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
No symbols are exported by default, but the following things are |
60
|
|
|
|
|
|
|
available for export: |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
Status values exported by the :status tag |
63
|
|
|
|
|
|
|
SUDOKU_SUCCESS |
64
|
|
|
|
|
|
|
This means what you think it does. |
65
|
|
|
|
|
|
|
SUDOKU_NO_SOLUTION |
66
|
|
|
|
|
|
|
This means the method exhausted all possible |
67
|
|
|
|
|
|
|
soltions without finding one |
68
|
|
|
|
|
|
|
SUDOKU_TOO_HARD |
69
|
|
|
|
|
|
|
This means the iteration_limit attribute was |
70
|
|
|
|
|
|
|
set to a positive number and the solution() |
71
|
|
|
|
|
|
|
method hit the limit without finding a solution. |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
The :all tag is provided for convenience, but it exports the same |
74
|
|
|
|
|
|
|
symbols as :status. |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=head2 Attributes |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
Games::Sudoku::General objects have the following attributes, which may |
79
|
|
|
|
|
|
|
normally be accessed by the get() method, and changed by the set() |
80
|
|
|
|
|
|
|
method. |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
In parentheses after the name of the attribute is the word "boolean", |
83
|
|
|
|
|
|
|
"number" or "string", giving the data type of the attribute. Booleans |
84
|
|
|
|
|
|
|
are interpreted in the Perl sense: undef, 0, and '' are false, and |
85
|
|
|
|
|
|
|
anything else is true. The parentheses may also contain the words |
86
|
|
|
|
|
|
|
"read-only" to denote a read-only attribute or "write-only" to denote |
87
|
|
|
|
|
|
|
a write-only attribute. |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
In general, the write-only attributes exist as a convenience to the |
90
|
|
|
|
|
|
|
user, and provide a shorthand way to set a cluster of attributes at |
91
|
|
|
|
|
|
|
the same time. At the moment all of them are concerned with generating |
92
|
|
|
|
|
|
|
problem topologies, which are a real pain to specify by hand. |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
=over |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
=item allowed_symbols (string) |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
This attribute names and defines sets of allowed symbols which may |
99
|
|
|
|
|
|
|
appear in empty cells. The set definitions are whitespace-delimited |
100
|
|
|
|
|
|
|
and each consists of a string of the form 'name=symbol,symbol...' |
101
|
|
|
|
|
|
|
where the 'name' is the name of the set, and the symbols are a list |
102
|
|
|
|
|
|
|
of the symbols valid in a cell to which that set applies. |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
For example, if you have an odd/even puzzle (i.e. you are given that |
105
|
|
|
|
|
|
|
at least some of the unoccupied cells are even or odd but not both), |
106
|
|
|
|
|
|
|
you might want to |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
$su->set (allowed_symbols => <
|
109
|
|
|
|
|
|
|
o=1,3,5,7,9 |
110
|
|
|
|
|
|
|
e=2,4,6,8 |
111
|
|
|
|
|
|
|
eod |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
and then define the problem like this: |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
$su->problem (<
|
116
|
|
|
|
|
|
|
1 o e o e e o e 3 |
117
|
|
|
|
|
|
|
o o e o 6 e o o e |
118
|
|
|
|
|
|
|
e e 3 o o 1 o e e |
119
|
|
|
|
|
|
|
e 7 o 1 o e e o e |
120
|
|
|
|
|
|
|
o e 8 e e o 5 o o |
121
|
|
|
|
|
|
|
o e o o e 3 e 4 o |
122
|
|
|
|
|
|
|
e o o 8 o o 6 o e |
123
|
|
|
|
|
|
|
o o o e 1 e e e o |
124
|
|
|
|
|
|
|
6 e e e o o o o 7 |
125
|
|
|
|
|
|
|
eod |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
To eliminate an individual allowed symbol set, set it to an empty |
128
|
|
|
|
|
|
|
string (e.g. $su->set (allowed_symbols => 'o=');). To eliminate all |
129
|
|
|
|
|
|
|
symbol sets, set the entire attribute to the empty string. |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
Allowed symbol set names may not conflict with symbol names. If you set |
132
|
|
|
|
|
|
|
the symbol attribute, all allowed symbol sets are deleted, because |
133
|
|
|
|
|
|
|
that seemed to be the most expeditious way to enforce this restriction |
134
|
|
|
|
|
|
|
across a symbol set change. |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
Because symbol set names must be parsed like symbol names when a |
137
|
|
|
|
|
|
|
problem is defined, they also affect the need for whitespace on |
138
|
|
|
|
|
|
|
problem input. See the L documentation for |
139
|
|
|
|
|
|
|
full details. |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=item autocopy (boolean) |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
If true, this attribute causes the generate() method to implicitly call |
144
|
|
|
|
|
|
|
copy() to copy the generated problem to the clipboard. |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
This attribute is false by default. |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=item brick (string, write-only) |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
This "virtual" attribute is a convenience, which causes the object to be |
151
|
|
|
|
|
|
|
configured with a topology of rows, columns, and rectangles. The value |
152
|
|
|
|
|
|
|
set must be either a comma-separated list of two numbers (e.g. '3,2') |
153
|
|
|
|
|
|
|
or a reference to a list containing two numbers (e.g. [3, 2]). Either |
154
|
|
|
|
|
|
|
way, the numbers represent the horizontal dimension of the rectangle (in |
155
|
|
|
|
|
|
|
columns) and the vertical dimension of the rectangle (in rows). The |
156
|
|
|
|
|
|
|
overall size of the puzzle square is the product of these. For example, |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
$su->set( brick => [ 3, 2 ] ) |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
generates a topology that looks like this |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
+-------+-------+ |
163
|
|
|
|
|
|
|
| x x x | x x x | |
164
|
|
|
|
|
|
|
| x x x | x x x | |
165
|
|
|
|
|
|
|
+-------+-------+ |
166
|
|
|
|
|
|
|
| x x x | x x x | |
167
|
|
|
|
|
|
|
| x x x | x x x | |
168
|
|
|
|
|
|
|
+-------+-------+ |
169
|
|
|
|
|
|
|
| x x x | x x x | |
170
|
|
|
|
|
|
|
| x x x | x x x | |
171
|
|
|
|
|
|
|
+-------+-------+ |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
Originally there was a third argument giving the total size of the |
174
|
|
|
|
|
|
|
puzzle. Beginning with version 0.006 this was deprecated, since it |
175
|
|
|
|
|
|
|
appeared to me to be redundant. As of version 0.021, all uses of this |
176
|
|
|
|
|
|
|
argument resulted in a warning. As of version 0.022, use of the third |
177
|
|
|
|
|
|
|
argument will become fatal. |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
Setting this attribute modifies the following "real" attributes: |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
columns is set to the size of the big square; |
182
|
|
|
|
|
|
|
symbols is set to "." and the numbers "1", "2", |
183
|
|
|
|
|
|
|
and so on, up to the size of the big square; |
184
|
|
|
|
|
|
|
topology is set to represent the rows, columns, |
185
|
|
|
|
|
|
|
and small rectangles in the big square, with row |
186
|
|
|
|
|
|
|
sets named "r0", "r1", and so on, column sets |
187
|
|
|
|
|
|
|
named "c0", "c1", and so on, and small |
188
|
|
|
|
|
|
|
rectangle sets named "s0", "s1", and so on for |
189
|
|
|
|
|
|
|
historical reasons. |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=item columns (number) |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
This attribute defines the number of columns of data to present in a |
194
|
|
|
|
|
|
|
line of output when formatting the topology attribute, or the solution |
195
|
|
|
|
|
|
|
to a puzzle. |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=item corresponding (number, write-only) |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
This "virtual" attribute is a convenience, which causes the object |
200
|
|
|
|
|
|
|
to be configured for "corresponding-cell" Sudoku. The topology is |
201
|
|
|
|
|
|
|
the same as C ... )>, but in addition corresponding |
202
|
|
|
|
|
|
|
cells in the small squares must have different values. The extra set |
203
|
|
|
|
|
|
|
names are "u0", "u1", and so on. |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
This kind of puzzle is also called "disjoint groups." |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=item cube (string, write-only) |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
This "virtual" attribute is a convenience, which causes the object to |
210
|
|
|
|
|
|
|
be configured for cubical sudoku. The string is either a number, or |
211
|
|
|
|
|
|
|
'full', or 'half'. |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
* a number sets the topology to a Dion cube of the given order. |
214
|
|
|
|
|
|
|
That is, |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sudokug> set cube 3 |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
generates a 9 x 9 x 9 Dion cube, with the small squares being 3 x 3. |
219
|
|
|
|
|
|
|
The problem is entered in plane, row, and column order, as though you |
220
|
|
|
|
|
|
|
were entering the required number of normal Sudoku puzzles |
221
|
|
|
|
|
|
|
back-to-back. |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
* 'full' generates a topology that includes all faces of the cube. The |
224
|
|
|
|
|
|
|
sets are the faces of the cube, and the rows, columns, and (for lack |
225
|
|
|
|
|
|
|
of a better word) planes of cells that circle the cube. |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
To enter the problem, imagine the cube unfolded to make a Latin cross. |
228
|
|
|
|
|
|
|
Then, enter the problem in order by faces, rows, and columns, top to |
229
|
|
|
|
|
|
|
bottom and left to right. The order of entry is actually by cell |
230
|
|
|
|
|
|
|
number, as given below. |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
+-------------+ |
233
|
|
|
|
|
|
|
| 0 1 2 3 | |
234
|
|
|
|
|
|
|
| 4 5 6 7 | |
235
|
|
|
|
|
|
|
| 8 9 10 11 | |
236
|
|
|
|
|
|
|
| 12 13 14 15 | |
237
|
|
|
|
|
|
|
+-------------+-------------+-------------+ |
238
|
|
|
|
|
|
|
| 16 17 18 19 | 32 33 34 35 | 48 49 50 51 | |
239
|
|
|
|
|
|
|
| 20 21 22 23 | 36 37 38 39 | 52 53 54 55 | |
240
|
|
|
|
|
|
|
| 24 25 26 27 | 40 41 42 43 | 56 57 58 59 | |
241
|
|
|
|
|
|
|
| 28 29 30 31 | 44 45 46 47 | 60 61 62 63 | |
242
|
|
|
|
|
|
|
+-------------+-------------+-------------+ |
243
|
|
|
|
|
|
|
| 64 65 66 67 | |
244
|
|
|
|
|
|
|
| 68 69 70 71 | |
245
|
|
|
|
|
|
|
| 72 73 74 75 | |
246
|
|
|
|
|
|
|
| 76 77 78 79 | |
247
|
|
|
|
|
|
|
+-------------+ |
248
|
|
|
|
|
|
|
| 80 81 82 83 | |
249
|
|
|
|
|
|
|
| 84 85 86 87 | |
250
|
|
|
|
|
|
|
| 88 89 90 91 | |
251
|
|
|
|
|
|
|
| 92 93 94 95 | |
252
|
|
|
|
|
|
|
+-------------+ |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
The solution will be displayed in order by cell number, with line |
255
|
|
|
|
|
|
|
breaks controlled by the C attribute, just |
256
|
|
|
|
|
|
|
like any other solution presented by this package. |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
I have seen such puzzles presented with the bottom square placed to the |
259
|
|
|
|
|
|
|
right and rotated counterclockwise 90 degrees. You will need to perform |
260
|
|
|
|
|
|
|
the opposite rotation when you enter the problem. |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
* 'half' generates a topology that looks like an isometric view of a |
263
|
|
|
|
|
|
|
cube, with the puzzle on the visible faces. The faces are divided in |
264
|
|
|
|
|
|
|
half, since the set size here is 8, not 16. Imagine the isometric |
265
|
|
|
|
|
|
|
unfolded to make an L-shape. Then, enter the problem in order by faces, |
266
|
|
|
|
|
|
|
rows, and columns, top to bottom and left to right. The order of entry |
267
|
|
|
|
|
|
|
is actually in order by cell number, as given below. |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
+-------------------+ |
270
|
|
|
|
|
|
|
| 0 1 2 3 | |
271
|
|
|
|
|
|
|
| | |
272
|
|
|
|
|
|
|
| 4 5 6 7 | |
273
|
|
|
|
|
|
|
+-------------------+ |
274
|
|
|
|
|
|
|
| 8 9 10 11 | |
275
|
|
|
|
|
|
|
| | |
276
|
|
|
|
|
|
|
| 12 13 14 15 | |
277
|
|
|
|
|
|
|
+---------+---------+-------------------+ |
278
|
|
|
|
|
|
|
| 16 17 | 18 19 | 32 33 34 35 | |
279
|
|
|
|
|
|
|
| | | | |
280
|
|
|
|
|
|
|
| 20 21 | 22 23 | 36 37 38 39 | |
281
|
|
|
|
|
|
|
| | +-------------------+ |
282
|
|
|
|
|
|
|
| 24 25 | 26 27 | 40 41 42 43 | |
283
|
|
|
|
|
|
|
| | | | |
284
|
|
|
|
|
|
|
| 28 29 | 30 31 | 44 45 46 47 | |
285
|
|
|
|
|
|
|
+---------+---------+-------------------+ |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
The solution will be displayed in order by cell number, with line |
288
|
|
|
|
|
|
|
breaks controlled by the C attribute, just |
289
|
|
|
|
|
|
|
like any other solution presented by this package. |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
For the 'full' and 'half' cube puzzles, the C attribute is |
292
|
|
|
|
|
|
|
set to 4, and the C attribute to the numbers 1 |
293
|
|
|
|
|
|
|
to the size of the largest set (16 for the full cube, 8 for the half |
294
|
|
|
|
|
|
|
or isometric cube). I have seen full cube puzzles done with hex digits |
295
|
|
|
|
|
|
|
0 to F; these are handled most easily by setting the |
296
|
|
|
|
|
|
|
C attribute appropriately: |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
$su->set (cube => 'full', symbols => <
|
299
|
|
|
|
|
|
|
. 0 1 2 3 4 5 6 7 8 9 A B C D E F |
300
|
|
|
|
|
|
|
eod |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
=item debug (number) |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
This attribute, if not 0, causes debugging information to be displayed. |
305
|
|
|
|
|
|
|
Values other than 0 are not supported, in the sense that the author |
306
|
|
|
|
|
|
|
makes no commitment what will happen when a non-zero value is set, and |
307
|
|
|
|
|
|
|
further reserves the right to change this behavior without notice of |
308
|
|
|
|
|
|
|
any sort, and without documenting the changes. |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=item generation_limit (number) |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
This attribute governs how hard the generate() method tries to generate |
313
|
|
|
|
|
|
|
a problem. If generate() cannot generate a problem after this number of |
314
|
|
|
|
|
|
|
tries, it gives up. |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
The default is 30. |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
=item iteration_limit (number) |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
This attribute governs how hard the solution() method tries to solve |
321
|
|
|
|
|
|
|
a problem. An iteration is an attempt to use the backtrack constraint. |
322
|
|
|
|
|
|
|
Since what this really counts is the number of times we place a |
323
|
|
|
|
|
|
|
backtrack constraint on the stack, not the number of values generated |
324
|
|
|
|
|
|
|
from that constraint, I suspect 10 to 20 is reasonable for a "normal" |
325
|
|
|
|
|
|
|
sudoku problem. |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
The default is 0, which imposes no limit. |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
=item largest_set (number, read-only) |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
This read-only attribute returns the size of the largest set defined by |
332
|
|
|
|
|
|
|
the current topology. |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
=item latin (number, write-only) |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
This "virtual" attribute is a convenience, which causes the object to |
337
|
|
|
|
|
|
|
be configured to handle a Latin square. The value gives the size of |
338
|
|
|
|
|
|
|
the square. Setting this modifies the following "real" attributes: |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
columns is set to the size of the square; |
341
|
|
|
|
|
|
|
symbols is set to "." and the letters "A", "B", |
342
|
|
|
|
|
|
|
and so on, up to the size of the square; |
343
|
|
|
|
|
|
|
topology is set to represent the rows and columns |
344
|
|
|
|
|
|
|
of a square, with row sets named "r0", "r1", |
345
|
|
|
|
|
|
|
and so on, and the column sets named "c0", |
346
|
|
|
|
|
|
|
"c1", and so on. |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
=item max_tuple (number) |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
This attribute represents the maximum-sized tuple to consider for the |
351
|
|
|
|
|
|
|
tuple constraint. It is possible that one might want to modify this |
352
|
|
|
|
|
|
|
upward for large puzzles, or downward for small ones. |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
The default is 4, meaning that the solution considers doubles, triples, |
355
|
|
|
|
|
|
|
and quads only. |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
=item name (string) |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
This attribute is for information, and is not used by the class. |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
=item null (string, write-only) |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
This "virtual" attribute is a convenience, which causes the object to |
364
|
|
|
|
|
|
|
be configured with the given number of cells, but no topology. The |
365
|
|
|
|
|
|
|
topology must be added later using the add_set method once for each |
366
|
|
|
|
|
|
|
set of cells to be created. |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
The value must be either a comma-separated list of one to three numbers |
369
|
|
|
|
|
|
|
(e.g. '81,9,9') or a reference to a list containing one to three |
370
|
|
|
|
|
|
|
numbers (e.g. [81, 9, 9]). The first (and only required) number gives the |
371
|
|
|
|
|
|
|
number of cells. The second, if supplied, sets the 'columns' attribute, |
372
|
|
|
|
|
|
|
and the third, if supplied, sets the 'rows' attribute. For example, |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
$su->set (null => [36, 6]); |
375
|
|
|
|
|
|
|
$su->add_set (r0 => 0, 1, 2, 3, 4, 5); |
376
|
|
|
|
|
|
|
$su->add_set (r1 => 6, 7, 8, 9, 10, 11); |
377
|
|
|
|
|
|
|
... |
378
|
|
|
|
|
|
|
$su->add_set (c0 => 0, 6, 12, 18, 24, 30); |
379
|
|
|
|
|
|
|
$su->add_set (c1 => 1, 7, 13, 19, 25, 31); |
380
|
|
|
|
|
|
|
... |
381
|
|
|
|
|
|
|
$su->add_set (s0 => 0, 1, 2, 6, 7, 8); |
382
|
|
|
|
|
|
|
$su->add_set (s1 => 3, 4, 5, 9, 10, 11); |
383
|
|
|
|
|
|
|
... |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
Generates the topology equivalent to |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
$su->set (brick => [3, 2]) |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
=item output_delimiter (string) |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
This attribute specifies the delimiter to be used between cell values |
392
|
|
|
|
|
|
|
on output. The default is a single space. |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
=item quincunx (text, write-only) |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
This "virtual" attribute is a convenience, which causes the object to be |
397
|
|
|
|
|
|
|
configured as a quincunx (a. k. a. 'Samurai Sudoku' at |
398
|
|
|
|
|
|
|
L). The value must be |
399
|
|
|
|
|
|
|
either a comma-separated list of one to two numbers (e.g. '3,1') or a |
400
|
|
|
|
|
|
|
reference to a list of one to two numbers (e.g. [3, 1]). In either case, |
401
|
|
|
|
|
|
|
the numbers are the order of the quincunx (3 corresponding to the usual |
402
|
|
|
|
|
|
|
'Samurai Sudoku' configuration), and the gap between the arms of the |
403
|
|
|
|
|
|
|
quincunx, in small squares. The gap must be strictly less than the |
404
|
|
|
|
|
|
|
order, and the same parity (odd or even) as the order. If the gap is not |
405
|
|
|
|
|
|
|
specified, it defaults to the smallest possible. |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
To be specific, |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
$su->set(quincunx => 3) |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
is equivalent to |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
$su->set(quincunx => [3, 1]) |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
and both specify the 'Samurai Sudoku' configuration. |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
The actual topology is set up as a square of (2 * order + gap) * order |
418
|
|
|
|
|
|
|
cells on a side, with the cells in the gap being unused. The sets used |
419
|
|
|
|
|
|
|
are the same as for sudoku of the same order, but with 'g0' through 'g4' |
420
|
|
|
|
|
|
|
prepended to their names, with g0 being the top left sudoku grid, g1 the |
421
|
|
|
|
|
|
|
top right, g2 the middle, g3 the bottom left, and g4 the bottom right. |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
In the case of the 's' sets, this would result in duplicate sets being |
424
|
|
|
|
|
|
|
generated in the overlap area, so the 's' set from the higher-numbered |
425
|
|
|
|
|
|
|
grid is suppressed. For example, in the 'Samurai Sudoku' configuration, |
426
|
|
|
|
|
|
|
sets g0s8, g1s6, g2s6, and g2s8 contain exactly the same cells as g2s0, |
427
|
|
|
|
|
|
|
g2s2, g3s2, and g4s0 respectively, so the latter are suppressed, and |
428
|
|
|
|
|
|
|
only the former appear in the topology. |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
Problems are specified left-to-right by rows. The cells in the gaps are |
431
|
|
|
|
|
|
|
unused, and are not specified. For example, the May 2, 2008 'Samurai |
432
|
|
|
|
|
|
|
Sudoku' problem could be specified as |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
. . . . . 1 . . . . . . 4 . . . . . |
435
|
|
|
|
|
|
|
. . . . 3 . 6 . . . . 7 . 2 . . . . |
436
|
|
|
|
|
|
|
. . . 7 . . . 5 . . 4 . . . 5 . . . |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
. . 6 9 . . . . 7 6 . . . . 9 1 . . |
439
|
|
|
|
|
|
|
. 5 . . 2 . . 4 . . 2 . . 5 . . 9 . |
440
|
|
|
|
|
|
|
4 . . . . 5 2 . . . . 8 1 . . . . 7 |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
. 2 . . . 4 . . . . 8 . . . . 3 . . . 2 . |
443
|
|
|
|
|
|
|
. . 5 . 6 . . . . 4 . 5 . . . . 8 . 4 . . |
444
|
|
|
|
|
|
|
. . . 1 . . . . . . 7 . . . . . . 7 . . . |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
. 4 . . 6 . . 2 . |
447
|
|
|
|
|
|
|
6 . 7 8 . 9 4 . 1 |
448
|
|
|
|
|
|
|
. 1 . . 4 . . 3 . |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
. . . 7 . . . . . . 9 . . . . . . 6 . . . |
451
|
|
|
|
|
|
|
. . 8 . 2 . . . . 2 . 8 . . . . 8 . 5 . . |
452
|
|
|
|
|
|
|
. 4 . . . 3 . . . . 5 . . . . 3 . . . 2 . |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
2 . . . . 7 8 . . . . 4 1 . . . . 6 |
455
|
|
|
|
|
|
|
. 3 . . 5 . . 4 . . 3 . . 2 . . 4 . |
456
|
|
|
|
|
|
|
. . 4 8 . . . . 7 2 . . . . 3 1 . . |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
. . . 9 . . . 1 . . 5 . . . 8 . . . |
459
|
|
|
|
|
|
|
. . . . 6 . 9 . . . . 7 . 4 . . . . |
460
|
|
|
|
|
|
|
. . . . . 4 . . . . . . 2 . . . . . |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
Setting this attribute causes the rows and columns attributes to be set |
463
|
|
|
|
|
|
|
to (2 * order + gap) * order. The symbols attribute is set to '.' and |
464
|
|
|
|
|
|
|
the numbers 1, 2, ... up to order * order. |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
=item rows (number) |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
This attribute defines the number of lines of output to present before |
469
|
|
|
|
|
|
|
inserting a blank line (for readability) when formatting the topology |
470
|
|
|
|
|
|
|
attribute, or the solution to a puzzle. |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
=item status_text (text, read-only) |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
This attribute is a short piece of text corresponding to the |
475
|
|
|
|
|
|
|
status_value. |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
=item status_value (number) |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
The solution() method sets a status, which can be retrieved via this |
480
|
|
|
|
|
|
|
attribute. The retrieved value is one of |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
SUDOKU_SUCCESS |
483
|
|
|
|
|
|
|
This means what you think it does. |
484
|
|
|
|
|
|
|
SUDOKU_NO_SOLUTION |
485
|
|
|
|
|
|
|
This means the method exhausted all possible |
486
|
|
|
|
|
|
|
soltions without finding one |
487
|
|
|
|
|
|
|
SUDOKU_TOO_HARD |
488
|
|
|
|
|
|
|
This means the iteration_limit attribute was |
489
|
|
|
|
|
|
|
set to a positive number and the solution() |
490
|
|
|
|
|
|
|
method hit the limit without finding a solution. |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
=item sudoku (number, write-only) |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
This attribute is a convenience, which causes the object to be |
495
|
|
|
|
|
|
|
configured to handle a standard Sudoku square. The value gives the size |
496
|
|
|
|
|
|
|
of the small squares into which the big square is divided. The big |
497
|
|
|
|
|
|
|
square's side is the square of the value. |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
For example, the customary Sudoku topology is set by |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
$su->set (sudoku => 3); |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
This attribute is implemented in terms of C ... )>, |
504
|
|
|
|
|
|
|
and modifies the same "real" attributes. See the C attribute for |
505
|
|
|
|
|
|
|
the details. |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
=item sudokux (number, write-only) |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
This attribute is a convenience. It is similar to the 'sudoku' |
510
|
|
|
|
|
|
|
attribute, but the topology includes both main diagonals (set names |
511
|
|
|
|
|
|
|
'd0' and 'd1') in addition to the standard sets. See the |
512
|
|
|
|
|
|
|
C attribute for the details, since that's ultimately how this |
513
|
|
|
|
|
|
|
attribute is implemented. |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
=item symbols (string) |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
This attribute defines the symbols to be used in the puzzle. Any |
518
|
|
|
|
|
|
|
printing characters may be used except ",". Multi-character symbols |
519
|
|
|
|
|
|
|
are supported. The value of the attribute is a whitespace-delimited |
520
|
|
|
|
|
|
|
list of the symbols, though the whitespace is optional if all symbols |
521
|
|
|
|
|
|
|
(and symbol constraints if any) are a single character. See the |
522
|
|
|
|
|
|
|
L documentation for full details. |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
The first symbol in the list is the one that represents an empty cell. |
525
|
|
|
|
|
|
|
Except for this, the order of the symbols is immaterial. |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
The symbols defined here are used only for input or output. It is |
528
|
|
|
|
|
|
|
perfectly legitimate to set symbols, call the problem() method, and |
529
|
|
|
|
|
|
|
then change the symbols. The solution() method will return solutions |
530
|
|
|
|
|
|
|
in the new symbol set. I have no idea why you would want to do this. |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
=item topology (string) |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
This attribute defines the topology of the puzzle, in terms of what |
535
|
|
|
|
|
|
|
sets each cell belongs to. Each cell is defined in terms of a |
536
|
|
|
|
|
|
|
comma-delimited list of the names of the sets it belongs to, and |
537
|
|
|
|
|
|
|
the string is a whitespace-delimited list of cell definitions. For |
538
|
|
|
|
|
|
|
example, a three-by-three grid with diagonals can be defined as |
539
|
|
|
|
|
|
|
follows in terms of sets r1, r2, and r3 for the rows, c1, c2, and |
540
|
|
|
|
|
|
|
c3 for the columns, and d1 and d2 for the diagonals: |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
r1,c1,d1 r1,c2 r1,c3,d2 |
543
|
|
|
|
|
|
|
r2,c1 r2,c2,d1,d2 r2,c3 |
544
|
|
|
|
|
|
|
r3,c1,d2 r3,c2 r3,c3,d1 |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
The parser treats line breaks as whitespace. That is to say, the |
547
|
|
|
|
|
|
|
above definition would be the same if it were all on one line. |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
You do not need to define the sets themselves anywhere. The |
550
|
|
|
|
|
|
|
package defines each set as it encounters it in the topology |
551
|
|
|
|
|
|
|
definition. |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
For certain topologies (e.g. the London Times Quincunx) it may be |
554
|
|
|
|
|
|
|
convenient to include in the definition cells that are not part of the |
555
|
|
|
|
|
|
|
puzzle. Such unused cells are defined by specifying just a comma, |
556
|
|
|
|
|
|
|
without any set names. |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
Setting the topology invalidates any currently-set-up problem. |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
=back |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
=head2 Methods |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
This package provides the following public methods: |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
=cut |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
package Games::Sudoku::General; |
569
|
|
|
|
|
|
|
|
570
|
2
|
|
|
2
|
|
2801
|
use 5.006002; # For 'our', at least. |
|
2
|
|
|
|
|
11
|
|
571
|
|
|
|
|
|
|
|
572
|
2
|
|
|
2
|
|
8
|
use strict; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
35
|
|
573
|
2
|
|
|
2
|
|
8
|
use warnings; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
64
|
|
574
|
|
|
|
|
|
|
|
575
|
2
|
|
|
2
|
|
17
|
use Exporter qw{ import }; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
181
|
|
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
our $VERSION = '0.027'; |
578
|
|
|
|
|
|
|
our @EXPORT_OK = qw{ |
579
|
|
|
|
|
|
|
SUDOKU_SUCCESS |
580
|
|
|
|
|
|
|
SUDOKU_NO_SOLUTION |
581
|
|
|
|
|
|
|
SUDOKU_TOO_HARD |
582
|
|
|
|
|
|
|
SUDOKU_MULTIPLE_SOLUTIONS |
583
|
|
|
|
|
|
|
}; |
584
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( |
585
|
|
|
|
|
|
|
all => \@EXPORT_OK, |
586
|
|
|
|
|
|
|
status => \@EXPORT_OK, |
587
|
|
|
|
|
|
|
); |
588
|
2
|
|
|
2
|
|
12
|
use Carp; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
140
|
|
589
|
2
|
|
|
2
|
|
1047
|
use Data::Dumper; |
|
2
|
|
|
|
|
11997
|
|
|
2
|
|
|
|
|
143
|
|
590
|
2
|
|
|
2
|
|
13
|
use List::Util qw{first max reduce}; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
200
|
|
591
|
2
|
|
|
2
|
|
841
|
use POSIX qw{floor}; |
|
2
|
|
|
|
|
12271
|
|
|
2
|
|
|
|
|
9
|
|
592
|
|
|
|
|
|
|
|
593
|
2
|
|
|
2
|
|
2564
|
use constant SUDOKU_SUCCESS => 0; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
112
|
|
594
|
2
|
|
|
2
|
|
10
|
use constant SUDOKU_NO_SOLUTION => 1; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
93
|
|
595
|
2
|
|
|
2
|
|
10
|
use constant SUDOKU_TOO_HARD => 2; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
71
|
|
596
|
2
|
|
|
2
|
|
9
|
use constant SUDOKU_MULTIPLE_SOLUTIONS => 3; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
148
|
|
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
my @status_values = ( |
599
|
|
|
|
|
|
|
'Success', |
600
|
|
|
|
|
|
|
'No solution found', |
601
|
|
|
|
|
|
|
'No solution found before exceeding iteration limit', |
602
|
|
|
|
|
|
|
'Multiple solutions found', |
603
|
|
|
|
|
|
|
); |
604
|
|
|
|
|
|
|
|
605
|
2
|
|
|
2
|
|
11
|
use constant HASH_REF => ref {}; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
18582
|
|
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
=head2 new |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
$su = Games::Sudoku::General->new () |
610
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
This method instantiates a new Games::Sudoku::General object. Any |
612
|
|
|
|
|
|
|
arguments are passed to the set() method. If, after processing |
613
|
|
|
|
|
|
|
the arguments, the object does not have a topology, |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
$self->set (sudoku => 3) |
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
is called. If there is no symbols setting (which could happen |
618
|
|
|
|
|
|
|
if the user passed an explicit topology), |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
$self->set (symbols => join ' ', '.', |
621
|
|
|
|
|
|
|
1 .. $self->get ('largest_set')) |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
is called. If, after all this, there is still no columns setting, |
624
|
|
|
|
|
|
|
the number of columns is set to the number of symbols, excluding |
625
|
|
|
|
|
|
|
the "empty cell" symbol. |
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
The newly-instantiated object is returned. |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
=cut |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
sub new { |
632
|
2
|
|
|
2
|
1
|
550
|
my ($class, @args) = @_; |
633
|
2
|
50
|
|
|
|
9
|
ref $class and $class = ref $class; |
634
|
2
|
|
|
|
|
11
|
my $self = bless { |
635
|
|
|
|
|
|
|
debug => 0, |
636
|
|
|
|
|
|
|
generation_limit => 30, |
637
|
|
|
|
|
|
|
iteration_limit => 0, |
638
|
|
|
|
|
|
|
output_delimiter => ' ', |
639
|
|
|
|
|
|
|
}, $class; |
640
|
2
|
50
|
|
|
|
7
|
@args and $self->set (@args); |
641
|
2
|
50
|
|
|
|
18
|
$self->{cell} or $self->set (sudoku => 3); |
642
|
|
|
|
|
|
|
$self->{symbol_list} |
643
|
2
|
50
|
|
|
|
7
|
or $self->set (symbols => join ' ', '.', 1 .. $self->{largest_set}); |
644
|
|
|
|
|
|
|
defined $self->{columns} |
645
|
2
|
50
|
|
|
|
17
|
or $self->set (columns => @{$self->{symbol_list}} - 1); |
|
0
|
|
|
|
|
0
|
|
646
|
|
|
|
|
|
|
defined $self->{status_value} |
647
|
2
|
50
|
|
|
|
13
|
or $self->set (status_value => SUDOKU_SUCCESS); |
648
|
|
|
|
|
|
|
defined $self->{max_tuple} |
649
|
2
|
50
|
|
|
|
8
|
or $self->set (max_tuple => 4); |
650
|
2
|
|
|
|
|
11
|
return $self; |
651
|
|
|
|
|
|
|
} |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
=head2 add_set |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
$su->add_set ($name => $cell ...) |
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
This method adds to the current topology a new set with the given name, |
658
|
|
|
|
|
|
|
and consisting of the given cells. The set name must not already |
659
|
|
|
|
|
|
|
exist, but the cells must already exist. In other words, you can't |
660
|
|
|
|
|
|
|
modify an existing set with this method, nor can you add new cells. |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
=cut |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
sub add_set { |
665
|
21
|
|
|
21
|
1
|
45
|
my ($self, $name, @cells) = @_; |
666
|
21
|
50
|
|
|
|
43
|
$self->{set}{$name} and croak <
|
667
|
|
|
|
|
|
|
Error - Set '$name' already exists. |
668
|
|
|
|
|
|
|
eod |
669
|
21
|
|
|
|
|
38
|
foreach my $inx (@cells) { |
670
|
184
|
50
|
|
|
|
282
|
$self->{cell}[$inx] or croak <
|
671
|
|
|
|
|
|
|
Error - Cell $inx does not exist. |
672
|
|
|
|
|
|
|
eod |
673
|
|
|
|
|
|
|
} |
674
|
21
|
|
|
|
|
27
|
foreach my $inx (@cells) { |
675
|
184
|
|
|
|
|
236
|
my $cell = $self->{cell}[$inx]; |
676
|
184
|
50
|
|
|
|
192
|
@{$cell->{membership}} or --$self->{cells_unused}; |
|
184
|
|
|
|
|
275
|
|
677
|
184
|
|
|
|
|
208
|
foreach my $other (@{$cell->{membership}}) { |
|
184
|
|
|
|
|
262
|
|
678
|
468
|
|
|
|
|
740
|
my $int = join ',', sort $other, $name; |
679
|
468
|
|
100
|
|
|
1301
|
$self->{intersection}{$int} ||= []; |
680
|
468
|
|
|
|
|
512
|
push @{$self->{intersection}{$int}}, $inx; |
|
468
|
|
|
|
|
802
|
|
681
|
|
|
|
|
|
|
} |
682
|
184
|
|
|
|
|
208
|
@{$cell->{membership}} = sort $name, @{$cell->{membership}}; |
|
184
|
|
|
|
|
446
|
|
|
184
|
|
|
|
|
273
|
|
683
|
|
|
|
|
|
|
} |
684
|
21
|
|
|
|
|
129
|
$self->{set}{$name} = { |
685
|
|
|
|
|
|
|
name => $name, |
686
|
|
|
|
|
|
|
membership => [sort @cells], |
687
|
|
|
|
|
|
|
}; |
688
|
|
|
|
|
|
|
$self->{largest_set} = max ($self->{largest_set}, |
689
|
21
|
|
|
|
|
32
|
scalar @{$self->{set}{$name}{membership}}); |
|
21
|
|
|
|
|
52
|
|
690
|
21
|
|
|
|
|
27
|
delete $self->{backtrack_stack}; # Force setting of new problem. |
691
|
21
|
|
|
|
|
51
|
return $self; |
692
|
|
|
|
|
|
|
} |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
=head2 constraints_used |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
%constraints_used = $su->constraints_used; |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
This method returns a hash containing the constraints used in the most |
699
|
|
|
|
|
|
|
recent call to solution(), and the number of times each was used. The |
700
|
|
|
|
|
|
|
constraint codes are the same as for the steps() method. If called in |
701
|
|
|
|
|
|
|
scalar context it returns a string representing the constraints used |
702
|
|
|
|
|
|
|
at least once, in canonical order (i.e. in the order documented in the |
703
|
|
|
|
|
|
|
steps() method). |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
B As of version 0.002, the string returned by the scalar has |
706
|
|
|
|
|
|
|
spaces delimiting the constraint names. They were not delimited in |
707
|
|
|
|
|
|
|
version 0.001 |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
=cut |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
sub constraints_used { |
712
|
6
|
|
|
6
|
1
|
16
|
my ( $self ) = @_; |
713
|
6
|
50
|
33
|
|
|
33
|
return unless $self->{constraints_used} && defined wantarray; |
714
|
6
|
50
|
|
|
|
14
|
return %{$self->{constraints_used}} if wantarray; |
|
0
|
|
|
|
|
0
|
|
715
|
|
|
|
|
|
|
my $rslt = join ' ', grep { |
716
|
6
|
|
|
|
|
16
|
$self->{constraints_used}{$_}} qw{F N B T X Y W ?}; |
|
48
|
|
|
|
|
80
|
|
717
|
6
|
|
|
|
|
24
|
return $rslt; |
718
|
|
|
|
|
|
|
} |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
=head2 copy |
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
$su->copy () |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
This method copies the current problem to the clipboard. If solution() |
725
|
|
|
|
|
|
|
has been called, the current solution goes on the clipboard. |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
See L for what is needed for this |
728
|
|
|
|
|
|
|
to work. |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
=cut |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
{ # Local symbol block. |
733
|
|
|
|
|
|
|
my $copier; |
734
|
|
|
|
|
|
|
sub copy { |
735
|
1
|
|
|
1
|
1
|
3
|
my ( $self ) = @_; |
736
|
1
|
50
|
33
|
|
|
4
|
( $copier ||= eval { |
737
|
1
|
|
|
|
|
373
|
require Clipboard; |
738
|
1
|
|
|
|
|
6
|
Clipboard->import(); |
739
|
|
|
|
|
|
|
sub { |
740
|
1
|
|
|
1
|
|
6
|
Clipboard->copy( join '', @_ ); |
741
|
1
|
|
|
|
|
2
|
return; |
742
|
1
|
|
|
|
|
8
|
}; |
743
|
|
|
|
|
|
|
} |
744
|
|
|
|
|
|
|
) or croak 'copy() unavailable; can not load Clipboard'; |
745
|
1
|
|
|
|
|
4
|
$copier->( $self->_unload() ); |
746
|
1
|
|
|
|
|
2
|
return $self; |
747
|
|
|
|
|
|
|
} |
748
|
|
|
|
|
|
|
} |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
=head2 drop_set |
751
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
$su->drop_set( $name ) |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
This method removes from the current topology the set with the given |
755
|
|
|
|
|
|
|
name. The set must exist, or an exception is raised. |
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
=cut |
758
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
sub drop_set { |
760
|
1
|
|
|
1
|
1
|
4
|
my ($self, $name) = @_; |
761
|
1
|
50
|
|
|
|
4
|
$self->{set}{$name} or croak <
|
762
|
|
|
|
|
|
|
Error - Set '$name' not defined. |
763
|
|
|
|
|
|
|
eod |
764
|
1
|
|
|
|
|
3
|
foreach my $inx (@{$self->{set}{$name}{membership}}) { |
|
1
|
|
|
|
|
5
|
|
765
|
4
|
|
|
|
|
8
|
my $cell = $self->{cell}[$inx]; |
766
|
4
|
|
|
|
|
6
|
my @mbr; |
767
|
4
|
|
|
|
|
5
|
foreach my $other (@{$cell->{membership}}) { |
|
4
|
|
|
|
|
8
|
|
768
|
12
|
100
|
|
|
|
20
|
if ($other ne $name) { |
769
|
8
|
|
|
|
|
11
|
push @mbr, $other; |
770
|
8
|
|
|
|
|
16
|
my $int = join ',', sort $other, $name; |
771
|
8
|
|
|
|
|
15
|
delete $self->{intersection}{$int}; |
772
|
|
|
|
|
|
|
} |
773
|
|
|
|
|
|
|
} |
774
|
4
|
50
|
|
|
|
9
|
if (@mbr) { |
775
|
4
|
|
|
|
|
7
|
@{$cell->{membership}} = sort @mbr; |
|
4
|
|
|
|
|
11
|
|
776
|
|
|
|
|
|
|
} else { |
777
|
0
|
|
|
|
|
0
|
@{$cell->{membership}} = (); |
|
0
|
|
|
|
|
0
|
|
778
|
0
|
|
|
|
|
0
|
$self->{cells_unused}++; |
779
|
|
|
|
|
|
|
} |
780
|
|
|
|
|
|
|
} |
781
|
1
|
|
|
|
|
3
|
delete $self->{set}{$name}; |
782
|
1
|
|
|
|
|
2
|
$self->{largest_set} = 0; |
783
|
1
|
|
|
|
|
3
|
foreach (keys %{$self->{set}}) { |
|
1
|
|
|
|
|
5
|
|
784
|
|
|
|
|
|
|
$self->{largest_set} = max ($self->{largest_set}, |
785
|
8
|
|
|
|
|
10
|
scalar @{$self->{set}{$_}{membership}}); |
|
8
|
|
|
|
|
19
|
|
786
|
|
|
|
|
|
|
} |
787
|
1
|
|
|
|
|
3
|
delete $self->{backtrack_stack}; # Force setting of new problem. |
788
|
1
|
|
|
|
|
3
|
return $self; |
789
|
|
|
|
|
|
|
} |
790
|
|
|
|
|
|
|
|
791
|
|
|
|
|
|
|
=head2 generate |
792
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
$problem = $su->generate( $min, $max, $const ); |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
This method generates a problem and returns it. |
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
The $min argument is the minimum number of givens in the puzzle. You |
798
|
|
|
|
|
|
|
may (and probably will) get more. The default is the number of cells |
799
|
|
|
|
|
|
|
in the puzzle divided by the number of sets a cell belongs to. |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
The value of this argument is critical to getting a puzzle: too large |
802
|
|
|
|
|
|
|
and you generate puzzles with no solution; too small and you spend all |
803
|
|
|
|
|
|
|
your time backtracking. There is no science behind the default, just an |
804
|
|
|
|
|
|
|
attempt to make a rational heuristic based on the number of degrees of |
805
|
|
|
|
|
|
|
freedom and the observation that about a third of the cells are given |
806
|
|
|
|
|
|
|
in a typical Sudoku puzzle. My experience with the default is: |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
topology comment |
809
|
|
|
|
|
|
|
brick 3,2 default is OK |
810
|
|
|
|
|
|
|
corresponding 3 default is OK |
811
|
|
|
|
|
|
|
cube 3 default is too large |
812
|
|
|
|
|
|
|
cube half default is OK |
813
|
|
|
|
|
|
|
cube full default is OK |
814
|
|
|
|
|
|
|
quincunx 3 default is too large |
815
|
|
|
|
|
|
|
sudoku 3 default is OK |
816
|
|
|
|
|
|
|
sudoku 4 default is OK |
817
|
|
|
|
|
|
|
sudokux 3 default is OK |
818
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
Typically when I take the defaults I get a puzzle in anywhere from |
820
|
|
|
|
|
|
|
a few seconds (most of the listed topologies) to a couple minutes |
821
|
|
|
|
|
|
|
(sudoku 4) on an 800 Mhz G4. But I have never successfully generated |
822
|
|
|
|
|
|
|
a Dion cube (cube 3). C |
823
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
The $max argument is the maximum number of givens in the puzzle. You |
825
|
|
|
|
|
|
|
may get less. The default is 1.5 times the minimum. |
826
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
The $const argument specifies the constraints to be used in the |
828
|
|
|
|
|
|
|
generated puzzle. This may be specified either as a string or as a hash |
829
|
|
|
|
|
|
|
reference. If specified as a string, it is a whitespace-delimited list, |
830
|
|
|
|
|
|
|
with each constraint name possibly followed by an equals sign and a |
831
|
|
|
|
|
|
|
number to specify that that constraint can be used only a certain |
832
|
|
|
|
|
|
|
number of times. For example, 'F N ?=1' specifies a puzzle to be |
833
|
|
|
|
|
|
|
solved by use of any number of applications of the F and N constraints, |
834
|
|
|
|
|
|
|
and at most one guessed cell. If specified as a hash reference, the |
835
|
|
|
|
|
|
|
keys are the constraint names, and the values are the usage counts, |
836
|
|
|
|
|
|
|
with undef meaning no limit. The hash reference corresponding to |
837
|
|
|
|
|
|
|
'F N ?=1' is {F => undef, N => undef, '?' => 1}. The default for this |
838
|
|
|
|
|
|
|
argument is to allow all known constraints except '?'. |
839
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
In practice, the generator usually generates puzzles solvable using |
841
|
|
|
|
|
|
|
only the F constraint, or the F and N constraints. |
842
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
The algorithm used is to generate a puzzle with the minimum number of |
844
|
|
|
|
|
|
|
cells selected at random, and then solve it. If a solution does not |
845
|
|
|
|
|
|
|
exist, we try again until we have tried |
846
|
|
|
|
|
|
|
C times, then we return undef. |
847
|
|
|
|
|
|
|
B |
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
If we get a solution, we remove allowed constraints. If we run into |
850
|
|
|
|
|
|
|
a constraint that is not allowed, we either stop (if we're below the |
851
|
|
|
|
|
|
|
maximum number of givens) or turn it into a given value (if we're |
852
|
|
|
|
|
|
|
above the maximum). We stop unconditionally if we get down to the |
853
|
|
|
|
|
|
|
minimum number of givens. As a side effect, the generated puzzle is |
854
|
|
|
|
|
|
|
set up as a problem. |
855
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
Note that if you allow guesses you may get puzzles with more than |
857
|
|
|
|
|
|
|
one solution. |
858
|
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
=cut |
860
|
|
|
|
|
|
|
|
861
|
|
|
|
|
|
|
sub generate { |
862
|
0
|
|
|
0
|
1
|
0
|
my ( $self, $min, $max, $const ) = @_; |
863
|
0
|
|
|
|
|
0
|
my $size = @{$self->{cell}} - $self->{cells_unused}; |
|
0
|
|
|
|
|
0
|
|
864
|
0
|
|
0
|
|
|
0
|
$min ||= do { |
865
|
|
|
|
|
|
|
floor( $size * $size / |
866
|
0
|
|
|
|
|
0
|
( $self->{largest_set} * keys %{ $self->{set} } ) ); |
|
0
|
|
|
|
|
0
|
|
867
|
|
|
|
|
|
|
}; |
868
|
0
|
|
0
|
|
|
0
|
$max ||= floor( $min * 1.5 ); |
869
|
0
|
|
0
|
|
|
0
|
$const ||= 'F N B T'; |
870
|
0
|
0
|
0
|
|
|
0
|
croak <<"EOD" if ref $const && HASH_REF ne ref $const; |
871
|
|
|
|
|
|
|
Error - The constraints argument must be a string or a hash reference, |
872
|
0
|
|
|
|
|
0
|
not a @{[ref $const]} reference. |
873
|
|
|
|
|
|
|
EOD |
874
|
0
|
0
|
|
|
|
0
|
$const = {map {my @ret; $_ and do { |
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
875
|
0
|
|
|
|
|
0
|
@ret = split '=', $_, 2; push @ret, undef while @ret < 2}; @ret} |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
876
|
|
|
|
|
|
|
split '\s+', $const} |
877
|
|
|
|
|
|
|
unless HASH_REF eq ref $const; |
878
|
0
|
0
|
|
|
|
0
|
$self->{debug} and do { |
879
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Terse = 1; |
880
|
0
|
|
|
|
|
0
|
print <
|
881
|
0
|
|
|
|
|
0
|
Debug generate ($min, $max, @{[Dumper $const]}) |
882
|
|
|
|
|
|
|
eod |
883
|
|
|
|
|
|
|
}; |
884
|
0
|
|
|
|
|
0
|
my $syms = @{$self->{symbol_list}} - 1; |
|
0
|
|
|
|
|
0
|
|
885
|
0
|
0
|
|
|
|
0
|
croak < $size; |
886
|
|
|
|
|
|
|
Error - You specified a minimum of $min given values, but the puzzle |
887
|
|
|
|
|
|
|
only contains $size cells. |
888
|
|
|
|
|
|
|
eod |
889
|
0
|
|
|
|
|
0
|
my $tries = $self->{generation_limit}; |
890
|
0
|
|
|
|
|
0
|
$size = @{$self->{cell}}; # Note equivocation on $size. |
|
0
|
|
|
|
|
0
|
|
891
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Terse = 1; |
892
|
|
|
|
|
|
|
my @universe = $self->{cells_unused} ? |
893
|
0
|
|
|
|
|
0
|
grep {@{$self->{cell}[$_]{membership}}} (0 .. @{$self->{cell}} - 1) : |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
894
|
0
|
0
|
|
|
|
0
|
(0 .. @{$self->{cell}} - 1); |
|
0
|
|
|
|
|
0
|
|
895
|
0
|
|
|
|
|
0
|
while (--$tries >= 0) { |
896
|
0
|
|
|
|
|
0
|
$self->problem (); # We rely on this specifying an empty problem. |
897
|
|
|
|
|
|
|
## my @ix = (0 .. $size - 1); |
898
|
0
|
|
|
|
|
0
|
my @ix = @universe; |
899
|
0
|
|
|
|
|
0
|
my $gen = 0; |
900
|
0
|
|
|
|
|
0
|
while ($gen++ < $min) { |
901
|
0
|
|
|
|
|
0
|
my ($inx) = splice @ix, floor (rand scalar @ix), 1; |
902
|
0
|
|
|
|
|
0
|
my $cell = $self->{cell}[$inx]; |
903
|
|
|
|
|
|
|
## @{$cell->{membership}} or redo; # Ignore unused cells. |
904
|
0
|
0
|
|
|
|
0
|
my @pos = grep {!$cell->{possible}{$_}} 1 .. $syms or next; |
|
0
|
|
|
|
|
0
|
|
905
|
0
|
|
|
|
|
0
|
my $val = $pos[floor (rand scalar @pos)]; |
906
|
0
|
0
|
|
|
|
0
|
defined $val or confess <{possible}); |
907
|
|
|
|
|
|
|
Programming error - generate() selected an undefined value for cell $inx. |
908
|
|
|
|
|
|
|
Possible values hash is: |
909
|
|
|
|
|
|
|
eod |
910
|
|
|
|
|
|
|
$self->_try ($cell, $val) |
911
|
0
|
0
|
|
|
|
0
|
and confess <{possible}); |
912
|
|
|
|
|
|
|
Programming error - generate() tried to assign $val to cell $inx, |
913
|
|
|
|
|
|
|
but it was rejected. Possible values hash is: |
914
|
|
|
|
|
|
|
eod |
915
|
|
|
|
|
|
|
} |
916
|
0
|
0
|
|
|
|
0
|
$self->solution () or next; |
917
|
0
|
|
|
|
|
0
|
$self->_constraint_remove ($min, $max, $const); |
918
|
0
|
|
|
|
|
0
|
my $prob = $self->_unload ('', SUDOKU_SUCCESS); |
919
|
0
|
|
|
|
|
0
|
$self->problem ($prob); |
920
|
0
|
0
|
|
|
|
0
|
$self->copy ($prob) if $self->{autocopy}; |
921
|
0
|
|
|
|
|
0
|
return $prob; |
922
|
|
|
|
|
|
|
} |
923
|
0
|
|
|
|
|
0
|
return; |
924
|
|
|
|
|
|
|
} |
925
|
|
|
|
|
|
|
|
926
|
|
|
|
|
|
|
my %accessor = ( |
927
|
|
|
|
|
|
|
allowed_symbols => \&_get_allowed_symbols, |
928
|
|
|
|
|
|
|
autocopy => \&_get_value, |
929
|
|
|
|
|
|
|
columns => \&_get_value, |
930
|
|
|
|
|
|
|
debug => \&_get_value, |
931
|
|
|
|
|
|
|
generation_limit => \&_get_value, |
932
|
|
|
|
|
|
|
## ignore_unused => \&_get_value, |
933
|
|
|
|
|
|
|
iteration_limit => \&_get_value, |
934
|
|
|
|
|
|
|
largest_set => \&_get_value, |
935
|
|
|
|
|
|
|
name => \&_get_value, |
936
|
|
|
|
|
|
|
output_delimiter => \&_get_value, |
937
|
|
|
|
|
|
|
rows => \&_get_value, |
938
|
|
|
|
|
|
|
status_text => \&_get_value, |
939
|
|
|
|
|
|
|
status_value => \&_get_value, |
940
|
|
|
|
|
|
|
symbols => \&_get_symbols, |
941
|
|
|
|
|
|
|
topology => \&_get_topology, |
942
|
|
|
|
|
|
|
); |
943
|
|
|
|
|
|
|
|
944
|
|
|
|
|
|
|
=head2 get |
945
|
|
|
|
|
|
|
|
946
|
|
|
|
|
|
|
$value = $su->get( $name ); |
947
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
This method returns the value of the named attribute. An exception |
949
|
|
|
|
|
|
|
is thrown if the given name does not correspond to an attribute that |
950
|
|
|
|
|
|
|
can be read. That is, the given name must appear on the list of |
951
|
|
|
|
|
|
|
attributes above, and not be marked "write-only". |
952
|
|
|
|
|
|
|
|
953
|
|
|
|
|
|
|
If called in list context, you can pass multiple attribute names, |
954
|
|
|
|
|
|
|
and get back a list of their values. If called in scalar context, |
955
|
|
|
|
|
|
|
attribute names after the first are ignored. |
956
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
=cut |
958
|
|
|
|
|
|
|
|
959
|
|
|
|
|
|
|
sub get { |
960
|
21
|
|
|
21
|
1
|
70
|
my ($self, @args) = @_; |
961
|
21
|
|
|
|
|
37
|
my @rslt; |
962
|
21
|
50
|
|
|
|
76
|
wantarray or @args = ($args[0]); |
963
|
21
|
|
|
|
|
40
|
foreach my $name (@args) { |
964
|
21
|
50
|
|
|
|
48
|
exists $accessor{$name} or croak <
|
965
|
|
|
|
|
|
|
Error - Attribute $name does not exist, or is write-only. |
966
|
|
|
|
|
|
|
eod |
967
|
21
|
|
|
|
|
63
|
push @rslt, $accessor{$name}->($self, $name); |
968
|
|
|
|
|
|
|
} |
969
|
21
|
50
|
|
|
|
107
|
return wantarray ? @rslt : $rslt[0]; |
970
|
|
|
|
|
|
|
} |
971
|
|
|
|
|
|
|
|
972
|
|
|
|
|
|
|
sub _get_allowed_symbols { |
973
|
2
|
|
|
2
|
|
6
|
my ( $self ) = @_; |
974
|
2
|
|
|
|
|
4
|
my $rslt = ''; |
975
|
2
|
|
|
|
|
3
|
my $syms = @{$self->{symbol_list}}; |
|
2
|
|
|
|
|
5
|
|
976
|
2
|
|
|
|
|
4
|
foreach (sort keys %{$self->{allowed_symbols}}) { |
|
2
|
|
|
|
|
15
|
|
977
|
6
|
|
|
|
|
7
|
my @symlst; |
978
|
6
|
|
|
|
|
13
|
for (my $val = 1; $val < $syms; $val++) { |
979
|
|
|
|
|
|
|
push @symlst, $self->{symbol_list}[$val] |
980
|
54
|
100
|
|
|
|
123
|
if $self->{allowed_symbols}{$_}[$val]; |
981
|
|
|
|
|
|
|
} |
982
|
6
|
|
|
|
|
12
|
$rslt .= "$_=@{[join ',', @symlst]}\n"; |
|
6
|
|
|
|
|
21
|
|
983
|
|
|
|
|
|
|
} |
984
|
2
|
|
|
|
|
11
|
return $rslt; |
985
|
|
|
|
|
|
|
} |
986
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
sub _get_symbols { |
988
|
5
|
|
|
5
|
|
11
|
my ( $self ) = @_; |
989
|
5
|
|
|
|
|
10
|
return join ' ', @{$self->{symbol_list}}; |
|
5
|
|
|
|
|
28
|
|
990
|
|
|
|
|
|
|
} |
991
|
|
|
|
|
|
|
|
992
|
|
|
|
|
|
|
sub _get_topology { |
993
|
8
|
|
|
8
|
|
40
|
my ( $self ) = @_; |
994
|
8
|
|
|
|
|
22
|
my $rslt = ''; |
995
|
8
|
|
|
|
|
19
|
my $col = $self->{columns}; |
996
|
8
|
|
33
|
|
|
24
|
my $row = $self->{rows} ||= floor (@{$self->{cell}} / $col); |
|
0
|
|
|
|
|
0
|
|
997
|
8
|
50
|
|
|
|
16
|
foreach (map {join (',', @{$_->{membership}}) || ','} @{$self->{cell}}) { |
|
583
|
|
|
|
|
656
|
|
|
583
|
|
|
|
|
1126
|
|
|
8
|
|
|
|
|
21
|
|
998
|
583
|
|
|
|
|
643
|
$rslt .= $_; |
999
|
583
|
100
|
|
|
|
707
|
if (--$col > 0) { |
1000
|
522
|
|
|
|
|
616
|
$rslt .= ' ' |
1001
|
|
|
|
|
|
|
} else { |
1002
|
61
|
|
|
|
|
72
|
$rslt .= "\n"; |
1003
|
61
|
|
|
|
|
78
|
$col = $self->{columns}; |
1004
|
61
|
100
|
|
|
|
115
|
if (--$row <= 0) { |
1005
|
8
|
|
|
|
|
14
|
$rslt .= "\n"; |
1006
|
8
|
|
|
|
|
14
|
$row = $self->{rows}; |
1007
|
|
|
|
|
|
|
} |
1008
|
|
|
|
|
|
|
} |
1009
|
|
|
|
|
|
|
} |
1010
|
8
|
|
|
|
|
54
|
0 while chomp $rslt; |
1011
|
8
|
|
|
|
|
16
|
$rslt .= "\n"; |
1012
|
8
|
|
|
|
|
43
|
return $rslt; |
1013
|
|
|
|
|
|
|
} |
1014
|
|
|
|
|
|
|
|
1015
|
6
|
|
|
6
|
|
19
|
sub _get_value {return $_[0]->{$_[1]}} |
1016
|
|
|
|
|
|
|
|
1017
|
|
|
|
|
|
|
=head2 paste |
1018
|
|
|
|
|
|
|
|
1019
|
|
|
|
|
|
|
$su->paste() |
1020
|
|
|
|
|
|
|
|
1021
|
|
|
|
|
|
|
This method pastes a problem from the clipboard. |
1022
|
|
|
|
|
|
|
|
1023
|
|
|
|
|
|
|
See L for what is needed for this |
1024
|
|
|
|
|
|
|
to work. |
1025
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
=cut |
1027
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
{ # Begin local symbol block |
1029
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
my $paster; |
1031
|
|
|
|
|
|
|
sub paste { |
1032
|
1
|
|
|
1
|
1
|
3
|
my ( $self ) = @_; |
1033
|
1
|
50
|
33
|
|
|
5
|
( $paster ||= eval { |
1034
|
1
|
|
|
|
|
5
|
require Clipboard; |
1035
|
1
|
|
|
|
|
4
|
Clipboard->import(); |
1036
|
|
|
|
|
|
|
return sub { |
1037
|
1
|
|
|
1
|
|
3
|
return Clipboard->paste(); |
1038
|
1
|
|
|
|
|
6
|
}; |
1039
|
|
|
|
|
|
|
} |
1040
|
|
|
|
|
|
|
) or croak 'paste() unavailable; can not load Clipboard'; |
1041
|
|
|
|
|
|
|
|
1042
|
1
|
|
|
|
|
4
|
$self->problem( $paster->() ); |
1043
|
1
|
|
|
|
|
3
|
$self->_unload(); |
1044
|
1
|
|
|
|
|
3
|
return $self; |
1045
|
|
|
|
|
|
|
} |
1046
|
|
|
|
|
|
|
|
1047
|
|
|
|
|
|
|
} # End local symbol block |
1048
|
|
|
|
|
|
|
|
1049
|
|
|
|
|
|
|
=head2 problem |
1050
|
|
|
|
|
|
|
|
1051
|
|
|
|
|
|
|
$su->problem( $string ); |
1052
|
|
|
|
|
|
|
|
1053
|
|
|
|
|
|
|
This method specifies the problem to be solved, and sets the object |
1054
|
|
|
|
|
|
|
up to solve the problem. |
1055
|
|
|
|
|
|
|
|
1056
|
|
|
|
|
|
|
The problem is specified by a whitespace-delimited list of the symbols |
1057
|
|
|
|
|
|
|
contained by each cell. You can format the puzzle definition into a |
1058
|
|
|
|
|
|
|
square grid (e.g. the SYNOPSIS section), but to the parser a line |
1059
|
|
|
|
|
|
|
break is no different than spaces. If you pass an empty string, an |
1060
|
|
|
|
|
|
|
empty problem will be set up - that is, one in which all cells are |
1061
|
|
|
|
|
|
|
empty. |
1062
|
|
|
|
|
|
|
|
1063
|
|
|
|
|
|
|
An exception will be thrown if: |
1064
|
|
|
|
|
|
|
|
1065
|
|
|
|
|
|
|
* The puzzle definition uses an unknown symbol; |
1066
|
|
|
|
|
|
|
* The puzzle definition has a different number |
1067
|
|
|
|
|
|
|
of cells from the topology definition; |
1068
|
|
|
|
|
|
|
* There exists a set with more members than the |
1069
|
|
|
|
|
|
|
number of symbols, excluding the "empty" |
1070
|
|
|
|
|
|
|
symbol. |
1071
|
|
|
|
|
|
|
|
1072
|
|
|
|
|
|
|
The whitespace delimiter is optional, provided that all symbol names |
1073
|
|
|
|
|
|
|
are exactly one character long, B that you have not defined any |
1074
|
|
|
|
|
|
|
symbol constraint names more than one character long since the last |
1075
|
|
|
|
|
|
|
time you set the symbol names. |
1076
|
|
|
|
|
|
|
|
1077
|
|
|
|
|
|
|
=cut |
1078
|
|
|
|
|
|
|
|
1079
|
|
|
|
|
|
|
sub problem { |
1080
|
19
|
|
|
19
|
1
|
73
|
my ( $self, $val ) = @_; |
1081
|
19
|
|
50
|
|
|
48
|
$val ||= ''; |
1082
|
|
|
|
|
|
|
$val =~ m/\S/ or |
1083
|
|
|
|
|
|
|
$val = "$self->{symbol_list}[0] " x |
1084
|
19
|
50
|
|
|
|
96
|
(scalar @{$self->{cell}} - $self->{cells_unused}); |
|
0
|
|
|
|
|
0
|
|
1085
|
19
|
100
|
|
|
|
294
|
$val =~ s/\s+//g unless $self->{biggest_spec} > 1; |
1086
|
19
|
|
|
|
|
58
|
$val =~ s/^\s+//; |
1087
|
19
|
|
|
|
|
77
|
$val =~ s/\s+$//; |
1088
|
19
|
50
|
|
|
|
69
|
$self->{debug} and print <
|
1089
|
|
|
|
|
|
|
Debug problem - Called with $val |
1090
|
|
|
|
|
|
|
eod |
1091
|
|
|
|
|
|
|
|
1092
|
19
|
|
|
|
|
41
|
local $Data::Dumper::Terse = 1; |
1093
|
19
|
50
|
|
|
|
31
|
$self->{largest_set} >= @{$self->{symbol_list}} and croak <
|
|
19
|
|
|
|
|
53
|
|
1094
|
|
|
|
|
|
|
Error - The largest set has $self->{largest_set} cells, but there are only @{[ |
1095
|
0
|
|
|
|
|
0
|
@{$self->{symbol_list}} - 1]} symbols. |
|
0
|
|
|
|
|
0
|
|
1096
|
|
|
|
|
|
|
Either the set definition is in error or the list of symbols is |
1097
|
|
|
|
|
|
|
incomplete. |
1098
|
|
|
|
|
|
|
eod |
1099
|
|
|
|
|
|
|
|
1100
|
19
|
|
|
|
|
26
|
my $syms = @{$self->{symbol_list}}; |
|
19
|
|
|
|
|
31
|
|
1101
|
19
|
|
|
|
|
27
|
foreach (@{$self->{cell}}) { |
|
19
|
|
|
|
|
42
|
|
1102
|
1651
|
|
|
|
|
2400
|
$_->{content} = $_->{chosen} = 0; |
1103
|
1651
|
|
|
|
|
2226
|
$_->{possible} = {map {$_ => 0} (1 .. $syms - 1)}; |
|
17167
|
|
|
|
|
26053
|
|
1104
|
|
|
|
|
|
|
} |
1105
|
19
|
|
|
|
|
44
|
foreach (values %{$self->{set}}) { |
|
19
|
|
|
|
|
77
|
|
1106
|
511
|
|
|
|
|
536
|
$_->{free} = @{$_->{membership}}; |
|
511
|
|
|
|
|
639
|
|
1107
|
511
|
|
|
|
|
842
|
$_->{content} = [$_->{free}]; |
1108
|
|
|
|
|
|
|
} |
1109
|
19
|
|
|
|
|
29
|
$self->{cells_unassigned} = scalar @{$self->{cell}} - $self->{cells_unused}; |
|
19
|
|
|
|
|
40
|
|
1110
|
|
|
|
|
|
|
|
1111
|
19
|
|
|
|
|
31
|
my $hash = $self->{symbol_hash}; |
1112
|
19
|
|
|
|
|
34
|
my $inx = 0; |
1113
|
19
|
|
|
|
|
30
|
my $max = @{$self->{cell}}; |
|
19
|
|
|
|
|
38
|
|
1114
|
19
|
100
|
|
|
|
485
|
foreach (split (($self->{biggest_spec} > 1 ? '\s+' : ''), $val)) { |
1115
|
1651
|
50
|
|
|
|
2316
|
$inx >= $max and croak <
|
1116
|
|
|
|
|
|
|
Error - Too many cell specifications. The topology allows only $max. |
1117
|
|
|
|
|
|
|
eod |
1118
|
1651
|
50
|
|
|
|
2272
|
next unless defined $_; |
1119
|
|
|
|
|
|
|
# was $self->{ignore_unused} |
1120
|
0
|
|
|
|
|
0
|
($self->{cells_unused} && !@{$self->{cell}[$inx]{membership}}) |
1121
|
1651
|
50
|
33
|
|
|
2466
|
and do {$inx++; redo}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1122
|
1651
|
100
|
|
|
|
2407
|
$self->{allowed_symbols}{$_} and do { |
1123
|
195
|
50
|
|
|
|
320
|
$self->{debug} > 1 and print <
|
1124
|
|
|
|
|
|
|
Debug problem - Cell $inx allows symbol set $_ |
1125
|
|
|
|
|
|
|
eod |
1126
|
195
|
|
|
|
|
228
|
my $cell = $self->{cell}[$inx]; |
1127
|
195
|
50
|
|
|
|
200
|
@{$cell->{membership}} or croak <
|
|
195
|
|
|
|
|
324
|
|
1128
|
|
|
|
|
|
|
Error - Cell $inx is unused, and must be specified as empty. |
1129
|
|
|
|
|
|
|
eod |
1130
|
195
|
|
|
|
|
322
|
for (my $val = 1; $val < $syms; $val++) { |
1131
|
1692
|
100
|
|
|
|
2740
|
next if $self->{allowed_symbols}{$_}[$val]; |
1132
|
749
|
|
|
|
|
1210
|
$cell->{possible}{$val} = 1; |
1133
|
|
|
|
|
|
|
} |
1134
|
|
|
|
|
|
|
}; |
1135
|
1651
|
100
|
|
|
|
2425
|
defined $hash->{$_} or $_ = $self->{symbol_list}[0]; |
1136
|
1651
|
|
|
|
|
2826
|
(@{$self->{cell}[$inx]{membership}} || |
1137
|
1651
|
50
|
33
|
|
|
1682
|
$_ eq $self->{symbol_list}[0]) |
1138
|
|
|
|
|
|
|
or croak <
|
1139
|
|
|
|
|
|
|
Error - Cell $inx is unused, and must be specified as empty. |
1140
|
|
|
|
|
|
|
eod |
1141
|
1651
|
50
|
|
|
|
2440
|
$self->{debug} > 1 and print <
|
1142
|
|
|
|
|
|
|
Debug problem - Cell $inx specifies symbol $_ |
1143
|
|
|
|
|
|
|
eod |
1144
|
1651
|
50
|
|
|
|
2438
|
$self->_try ($inx, $hash->{$_}) and croak <
|
1145
|
|
|
|
|
|
|
Error - Symbol '$_' appears more than once in a set. |
1146
|
|
|
|
|
|
|
The problem loaded thus far is: |
1147
|
0
|
|
|
|
|
0
|
@{[$self->_unload (' ')]} |
1148
|
|
|
|
|
|
|
eod |
1149
|
1651
|
100
|
|
|
|
2745
|
$self->{cell}[$inx]{chosen} = $hash->{$_} ? 1 : 0; |
1150
|
|
|
|
|
|
|
} continue { |
1151
|
1651
|
|
|
|
|
2127
|
$inx++; |
1152
|
|
|
|
|
|
|
} |
1153
|
|
|
|
|
|
|
|
1154
|
19
|
50
|
|
|
|
138
|
unless ($inx == $max) { |
1155
|
|
|
|
|
|
|
# was $self->{ignore_unused} |
1156
|
0
|
0
|
|
|
|
0
|
$self->{cells_unused} and do { |
1157
|
0
|
|
|
|
|
0
|
$inx -= $self->{cells_unused}; |
1158
|
0
|
|
|
|
|
0
|
$max -= $self->{cells_unused}; |
1159
|
|
|
|
|
|
|
}; |
1160
|
0
|
|
|
|
|
0
|
croak <
|
1161
|
|
|
|
|
|
|
Error - Not enough cell specifications. you gave $inx but the topology |
1162
|
|
|
|
|
|
|
defined $max. |
1163
|
|
|
|
|
|
|
eod |
1164
|
|
|
|
|
|
|
} |
1165
|
|
|
|
|
|
|
|
1166
|
19
|
|
|
|
|
62
|
$self->{constraints_used} = {}; |
1167
|
|
|
|
|
|
|
|
1168
|
19
|
50
|
|
|
|
42
|
$self->{debug} and print <
|
1169
|
|
|
|
|
|
|
Debug problem - problem loaded. |
1170
|
|
|
|
|
|
|
eod |
1171
|
|
|
|
|
|
|
|
1172
|
19
|
|
|
|
|
149
|
$self->{backtrack_stack} = []; |
1173
|
19
|
|
|
|
|
43
|
$self->{cell_order} = []; |
1174
|
19
|
|
|
|
|
29
|
delete $self->{no_more_solutions}; |
1175
|
|
|
|
|
|
|
|
1176
|
19
|
50
|
|
|
|
38
|
$self->{debug} > 1 and print " object = ", Dumper ($self); |
1177
|
|
|
|
|
|
|
|
1178
|
19
|
|
|
|
|
62
|
return $self; |
1179
|
|
|
|
|
|
|
} |
1180
|
|
|
|
|
|
|
|
1181
|
|
|
|
|
|
|
my %mutator = ( |
1182
|
|
|
|
|
|
|
allowed_symbols => \&_set_allowed_symbols, |
1183
|
|
|
|
|
|
|
autocopy => \&_set_value, |
1184
|
|
|
|
|
|
|
brick => \&_set_brick, |
1185
|
|
|
|
|
|
|
columns => \&_set_number, |
1186
|
|
|
|
|
|
|
debug => \&_set_number, |
1187
|
|
|
|
|
|
|
corresponding => \&_set_corresponding, |
1188
|
|
|
|
|
|
|
cube => \&_set_cube, |
1189
|
|
|
|
|
|
|
generation_limit => \&_set_number, |
1190
|
|
|
|
|
|
|
## ignore_unused => \&_set_value, |
1191
|
|
|
|
|
|
|
iteration_limit => \&_set_number, |
1192
|
|
|
|
|
|
|
latin => \&_set_latin, |
1193
|
|
|
|
|
|
|
max_tuple => \&_set_number, |
1194
|
|
|
|
|
|
|
name => \&_set_value, |
1195
|
|
|
|
|
|
|
null => \&_set_null, |
1196
|
|
|
|
|
|
|
output_delimiter => \&_set_value, |
1197
|
|
|
|
|
|
|
quincunx => \&_set_quincunx, |
1198
|
|
|
|
|
|
|
rows => \&_set_number, |
1199
|
|
|
|
|
|
|
status_value => \&_set_status_value, |
1200
|
|
|
|
|
|
|
sudoku => \&_set_sudoku, |
1201
|
|
|
|
|
|
|
sudokux => \&_set_sudokux, |
1202
|
|
|
|
|
|
|
symbols => \&_set_symbols, |
1203
|
|
|
|
|
|
|
topology => \&_set_topology, |
1204
|
|
|
|
|
|
|
); |
1205
|
|
|
|
|
|
|
|
1206
|
|
|
|
|
|
|
=head2 set |
1207
|
|
|
|
|
|
|
|
1208
|
|
|
|
|
|
|
$su->set( $name => $value ); |
1209
|
|
|
|
|
|
|
|
1210
|
|
|
|
|
|
|
This method sets the value of the named attribute. An exception |
1211
|
|
|
|
|
|
|
is thrown if the given name does not correspond to an attribute that |
1212
|
|
|
|
|
|
|
can be written. That is, the given name must appear on the list of |
1213
|
|
|
|
|
|
|
attributes above, and not be marked "read-only". An exception is |
1214
|
|
|
|
|
|
|
also thrown if the value is invalid, e.g. a non-numeric value for |
1215
|
|
|
|
|
|
|
an attribute marked "number". |
1216
|
|
|
|
|
|
|
|
1217
|
|
|
|
|
|
|
You can pass multiple name-value pairs. If an exception is thrown, |
1218
|
|
|
|
|
|
|
all settings before the exception will be made, and all settings |
1219
|
|
|
|
|
|
|
after the exception will not be made. |
1220
|
|
|
|
|
|
|
|
1221
|
|
|
|
|
|
|
The object itself is returned. |
1222
|
|
|
|
|
|
|
|
1223
|
|
|
|
|
|
|
=cut |
1224
|
|
|
|
|
|
|
|
1225
|
|
|
|
|
|
|
sub set { |
1226
|
62
|
|
|
62
|
1
|
183
|
my ( $self, @args ) = @_; |
1227
|
62
|
|
|
|
|
128
|
while ( @args ) { |
1228
|
90
|
|
|
|
|
204
|
my ( $name, $val ) = splice @args, 0, 2; |
1229
|
90
|
50
|
|
|
|
220
|
exists $mutator{$name} or croak <
|
1230
|
|
|
|
|
|
|
Error - Attribute $name does not exist, or is read-only. |
1231
|
|
|
|
|
|
|
eod |
1232
|
90
|
|
|
|
|
215
|
$mutator{$name}->($self, $name, $val ); |
1233
|
|
|
|
|
|
|
} |
1234
|
62
|
|
|
|
|
101
|
return $self; |
1235
|
|
|
|
|
|
|
} |
1236
|
|
|
|
|
|
|
|
1237
|
|
|
|
|
|
|
sub _set_allowed_symbols { |
1238
|
|
|
|
|
|
|
## my ( $self, $name, $value ) = @_; |
1239
|
4
|
|
|
4
|
|
11
|
my ( $self, undef, $value ) = @_; # Name unused |
1240
|
4
|
50
|
|
|
|
11
|
defined $value or $value = ''; |
1241
|
4
|
|
|
|
|
9
|
my $maxlen = 0; |
1242
|
4
|
50
|
|
|
|
13
|
$self->{debug} and print <
|
1243
|
|
|
|
|
|
|
Debug allowed_symbols being set to '$value' |
1244
|
|
|
|
|
|
|
eod |
1245
|
4
|
50
|
|
|
|
10
|
if ($value) { |
1246
|
4
|
|
|
|
|
32
|
foreach (split '\s+', $value) { |
1247
|
22
|
|
|
|
|
48
|
my ($name, $value) = split '=', $_, 2; |
1248
|
22
|
50
|
|
|
|
46
|
croak <{symbol_hash}{$name}; |
1249
|
|
|
|
|
|
|
Error - You can not use '$name' as a symbol constraint name, because |
1250
|
|
|
|
|
|
|
it is a valid symbol name. |
1251
|
|
|
|
|
|
|
eod |
1252
|
22
|
100
|
|
|
|
37
|
$value or do {delete $self->{allowed_symbols}{$name}; next}; |
|
2
|
|
|
|
|
14
|
|
|
2
|
|
|
|
|
4
|
|
1253
|
20
|
|
|
|
|
39
|
$maxlen = max ($maxlen, length ($name)); |
1254
|
20
|
50
|
|
|
|
36
|
$self->{debug} > 1 and print <
|
1255
|
|
|
|
|
|
|
Debug allowed_symbols - $_ |
1256
|
0
|
|
|
|
|
0
|
set name '$name' has length @{[length ($name)]}. Maxlen now $maxlen. |
1257
|
|
|
|
|
|
|
eod |
1258
|
20
|
|
|
|
|
53
|
my $const = $self->{allowed_symbols}{$name} = []; |
1259
|
20
|
|
|
|
|
45
|
foreach (split ',', $value) { |
1260
|
93
|
50
|
|
|
|
146
|
$self->{debug} > 1 and print <
|
1261
|
|
|
|
|
|
|
Debug allowed_symbols - Adding symbol '$_' to set '$name'. |
1262
|
|
|
|
|
|
|
eod |
1263
|
93
|
50
|
|
|
|
134
|
$self->{symbol_hash}{$_} or croak <
|
1264
|
|
|
|
|
|
|
Error - '$_' is not a valid symbol. |
1265
|
|
|
|
|
|
|
eod |
1266
|
93
|
|
|
|
|
157
|
$const->[$self->{symbol_hash}{$_}] = 1; |
1267
|
|
|
|
|
|
|
} |
1268
|
|
|
|
|
|
|
} |
1269
|
|
|
|
|
|
|
} else { |
1270
|
0
|
|
|
|
|
0
|
$self->{allowed_symbols} = {}; |
1271
|
|
|
|
|
|
|
} |
1272
|
4
|
100
|
|
|
|
16
|
$self->{biggest_spec} = $maxlen if $maxlen > $self->{biggest_spec}; |
1273
|
4
|
|
|
|
|
13
|
return; |
1274
|
|
|
|
|
|
|
} |
1275
|
|
|
|
|
|
|
|
1276
|
|
|
|
|
|
|
sub _set_brick { |
1277
|
6
|
|
|
6
|
|
20
|
my ( $self, undef, $value ) = @_; # $name unused |
1278
|
6
|
100
|
|
|
|
24
|
my ($horiz, $vert, $size) = ref $value ? @$value : split ',', $value; |
1279
|
6
|
50
|
|
|
|
21
|
defined $size |
1280
|
|
|
|
|
|
|
and $self->_deprecation_notice( 'brick_third_argument' ); |
1281
|
6
|
|
33
|
|
|
50
|
$size ||= $horiz * $vert; |
1282
|
6
|
50
|
33
|
|
|
41
|
($size % $horiz || $size % $vert) and croak <
|
1283
|
|
|
|
|
|
|
Error - The puzzle size $size must be a multiple of both the horizontal |
1284
|
|
|
|
|
|
|
brick size $horiz and the vertical brick size $vert. |
1285
|
|
|
|
|
|
|
eod |
1286
|
6
|
|
|
|
|
66
|
my $rowmul = floor ($size / $horiz); |
1287
|
6
|
|
|
|
|
17
|
my $syms = '.'; |
1288
|
6
|
|
|
|
|
12
|
my $topo = ''; |
1289
|
6
|
|
|
|
|
36
|
for (my $row = 0; $row < $size; $row++) { |
1290
|
58
|
|
|
|
|
76
|
$syms .= " @{[$row + 1]}"; |
|
58
|
|
|
|
|
124
|
|
1291
|
58
|
|
|
|
|
111
|
for (my $col = 0; $col < $size; $col++) { |
1292
|
616
|
|
|
|
|
1789
|
$topo .= sprintf ' r%d,c%d,s%d', $row, $col, |
1293
|
|
|
|
|
|
|
floor ($row / $vert) * $rowmul + floor ($col / $horiz); |
1294
|
|
|
|
|
|
|
} |
1295
|
|
|
|
|
|
|
} |
1296
|
6
|
|
|
|
|
18
|
substr ($topo, 0, 1, ''); |
1297
|
6
|
|
|
|
|
23
|
$self->set (columns => $size, rows => $size, symbols => $syms, |
1298
|
|
|
|
|
|
|
topology => $topo); |
1299
|
6
|
|
|
|
|
18
|
return; |
1300
|
|
|
|
|
|
|
} |
1301
|
|
|
|
|
|
|
|
1302
|
|
|
|
|
|
|
sub _set_corresponding { |
1303
|
|
|
|
|
|
|
## my ( $self, $name, $order ) = @_; |
1304
|
1
|
|
|
1
|
|
4
|
my ( $self, undef, $order ) = @_; # Name unused |
1305
|
1
|
|
|
|
|
4
|
my $size = $order * $order; |
1306
|
1
|
|
|
|
|
5
|
$self->set (sudoku => $order); |
1307
|
1
|
|
|
|
|
3
|
my $order_minus_1 = $order - 1; |
1308
|
1
|
|
|
|
|
3
|
my $offset = $size * $order; |
1309
|
1
|
|
|
|
|
6
|
for (my $inx = 0; $inx < $size; $inx++) { |
1310
|
9
|
|
|
|
|
27
|
my $base = floor ($inx / $order) * $size + $inx % $order; |
1311
|
|
|
|
|
|
|
$self->add_set ("u$inx", map { |
1312
|
9
|
|
|
|
|
19
|
my $g = $_ * $offset + $base; |
|
27
|
|
|
|
|
32
|
|
1313
|
27
|
|
|
|
|
30
|
(map {$_ * $order + $g} 0 .. $order_minus_1)} 0 .. $order_minus_1); |
|
81
|
|
|
|
|
120
|
|
1314
|
|
|
|
|
|
|
} |
1315
|
1
|
|
|
|
|
3
|
return; |
1316
|
|
|
|
|
|
|
} |
1317
|
|
|
|
|
|
|
|
1318
|
|
|
|
|
|
|
my %cube = ( |
1319
|
|
|
|
|
|
|
full => <
|
1320
|
|
|
|
|
|
|
c0,r0,s0 c1,r0,s0 c2,r0,s0 c3,r0,s0 |
1321
|
|
|
|
|
|
|
c0,r1,s0 c1,r1,s0 c2,r1,s0 c3,r1,s0 |
1322
|
|
|
|
|
|
|
c0,r2,s0 c1,r2,s0 c2,r2,s0 c3,r2,s0 |
1323
|
|
|
|
|
|
|
c0,r3,s0 c1,r3,s0 c2,r3,s0 c3,r3,s0 |
1324
|
|
|
|
|
|
|
p0,r0,s1 p0,r1,s1 p0,r2,s1 p0,r3,s1 |
1325
|
|
|
|
|
|
|
p1,r0,s1 p1,r1,s1 p1,r2,s1 p1,r3,s1 |
1326
|
|
|
|
|
|
|
p2,r0,s1 p2,r1,s1 p2,r2,s1 p2,r3,s1 |
1327
|
|
|
|
|
|
|
p3,r0,s1 p3,r1,s1 p3,r2,s1 p3,r3,s1 |
1328
|
|
|
|
|
|
|
c0,p0,s2 c1,p0,s2 c2,p0,s2 c3,p0,s2 |
1329
|
|
|
|
|
|
|
c0,p1,s2 c1,p1,s2 c2,p1,s2 c3,p1,s2 |
1330
|
|
|
|
|
|
|
c0,p2,s2 c1,p2,s2 c2,p2,s2 c3,p2,s2 |
1331
|
|
|
|
|
|
|
c0,p3,s2 c1,p3,s2 c2,p3,s2 c3,p3,s2 |
1332
|
|
|
|
|
|
|
p0,r3,s3 p0,r2,s3 p0,r1,s3 p0,r0,s3 |
1333
|
|
|
|
|
|
|
p1,r3,s3 p1,r2,s3 p1,r1,s3 p1,r0,s3 |
1334
|
|
|
|
|
|
|
p2,r3,s3 p2,r2,s3 p2,r1,s3 p2,r0,s3 |
1335
|
|
|
|
|
|
|
p3,r3,s3 p3,r2,s3 p3,r1,s3 p3,r0,s3 |
1336
|
|
|
|
|
|
|
c0,r3,s4 c1,r3,s4 c2,r3,s4 c3,r3,s4 |
1337
|
|
|
|
|
|
|
c0,r2,s4 c1,r2,s4 c2,r2,s4 c3,r2,s4 |
1338
|
|
|
|
|
|
|
c0,r1,s4 c1,r1,s4 c2,r1,s4 c3,r1,s4 |
1339
|
|
|
|
|
|
|
c0,r0,s4 c1,r0,s4 c2,r0,s4 c3,r0,s4 |
1340
|
|
|
|
|
|
|
c0,p3,s5 c1,p3,s5 c2,p3,s5 c3,p3,s5 |
1341
|
|
|
|
|
|
|
c0,p2,s5 c1,p2,s5 c2,p2,s5 c3,p2,s5 |
1342
|
|
|
|
|
|
|
c0,p1,s5 c1,p1,s5 c2,p1,s5 c3,p1,s5 |
1343
|
|
|
|
|
|
|
c0,p0,s5 c1,p0,s5 c2,p0,s5 c3,p0,s5 |
1344
|
|
|
|
|
|
|
eod |
1345
|
|
|
|
|
|
|
half => <
|
1346
|
|
|
|
|
|
|
r0,c0,s0 r0,c1,s0 r0,c2,s0 r0,c3,s0 |
1347
|
|
|
|
|
|
|
r1,c0,s0 r1,c1,s0 r1,c2,s0 r1,c3,s0 |
1348
|
|
|
|
|
|
|
r2,c0,s1 r2,c1,s1 r2,c2,s1 r2,c3,s1 |
1349
|
|
|
|
|
|
|
r3,c0,s1 r3,c1,s1 r3,c2,s1 r3,c3,s1 |
1350
|
|
|
|
|
|
|
p0,c0,s2 p0,c1,s2 p0,c2,s3 p0,c3,s3 |
1351
|
|
|
|
|
|
|
p1,c0,s2 p1,c1,s2 p1,c2,s3 p1,c3,s3 |
1352
|
|
|
|
|
|
|
p2,c0,s2 p2,c1,s2 p2,c2,s3 p2,c3,s3 |
1353
|
|
|
|
|
|
|
p3,c0,s2 p3,c1,s2 p3,c2,s3 p3,c3,s3 |
1354
|
|
|
|
|
|
|
p0,r3,s4 p0,r2,s4 p0,r1,s4 p0,r0,s4 |
1355
|
|
|
|
|
|
|
p1,r3,s4 p1,r2,s4 p1,r1,s4 p1,r0,s4 |
1356
|
|
|
|
|
|
|
p2,r3,s5 p2,r2,s5 p2,r1,s5 p2,r0,s5 |
1357
|
|
|
|
|
|
|
p3,r3,s5 p3,r2,s5 p3,r1,s5 p3,r0,s5 |
1358
|
|
|
|
|
|
|
eod |
1359
|
|
|
|
|
|
|
); |
1360
|
|
|
|
|
|
|
|
1361
|
|
|
|
|
|
|
sub _set_cube { |
1362
|
|
|
|
|
|
|
## my ( $self, $name, $type ) = @_; |
1363
|
2
|
|
|
2
|
|
19
|
my ( $self, undef, $type ) = @_; # Name unused |
1364
|
2
|
50
|
|
|
|
13
|
if ($type =~ m/\D/) { |
1365
|
2
|
50
|
|
|
|
7
|
$cube{$type} or croak <
|
1366
|
|
|
|
|
|
|
Error - Cube type '$type' is not defined. Legal values are numeric (for |
1367
|
0
|
|
|
|
|
0
|
Dion cube), or one of @{[join ', ', map {"'$_'"} sort keys %cube]} |
|
0
|
|
|
|
|
0
|
|
1368
|
|
|
|
|
|
|
eod |
1369
|
2
|
|
|
|
|
7
|
$self->set (topology => $cube{$type}, columns => 4, rows => 4); |
1370
|
|
|
|
|
|
|
} else { |
1371
|
0
|
|
|
|
|
0
|
my $size = $type * $type; |
1372
|
0
|
|
|
|
|
0
|
my $topo = ''; |
1373
|
0
|
|
|
|
|
0
|
for (my $x = 0; $x < $size; $x++) { |
1374
|
0
|
|
|
|
|
0
|
for (my $y = 0; $y < $size; $y++) { |
1375
|
0
|
|
|
|
|
0
|
for (my $z = 0; $z < $size; $z++) { |
1376
|
0
|
|
|
|
|
0
|
$topo .= join (',', |
1377
|
|
|
|
|
|
|
_cube_set_names ($type, x => $x, $y, $z), |
1378
|
|
|
|
|
|
|
_cube_set_names ($type, y => $y, $z, $x), |
1379
|
|
|
|
|
|
|
_cube_set_names ($type, z => $z, $x, $y)) . ' '; |
1380
|
|
|
|
|
|
|
} |
1381
|
|
|
|
|
|
|
} |
1382
|
|
|
|
|
|
|
} |
1383
|
0
|
|
|
|
|
0
|
$self->set (topology => $topo, columns => $size, rows => $size); |
1384
|
|
|
|
|
|
|
} |
1385
|
2
|
|
|
|
|
18
|
$self->set (symbols => join ' ', '.', 1 .. $self->{largest_set}); |
1386
|
2
|
|
|
|
|
5
|
return; |
1387
|
|
|
|
|
|
|
} |
1388
|
|
|
|
|
|
|
|
1389
|
|
|
|
|
|
|
sub _cube_set_names { |
1390
|
0
|
|
|
0
|
|
0
|
my ( $order, $name, $x, $y, $z ) = @_; |
1391
|
0
|
|
|
|
|
0
|
my $tplt = sprintf '%s%d%%s%%d', $name, $x; |
1392
|
0
|
|
|
|
|
0
|
return map {sprintf $tplt, @$_} [r => $y], [c => $z], |
|
0
|
|
|
|
|
0
|
|
1393
|
|
|
|
|
|
|
[s => floor ($y / $order) * $order + floor ($z / $order)] |
1394
|
|
|
|
|
|
|
} |
1395
|
|
|
|
|
|
|
|
1396
|
|
|
|
|
|
|
sub _set_latin { |
1397
|
|
|
|
|
|
|
## my ( $self, $name, $size ) = @_; |
1398
|
2
|
|
|
2
|
|
6
|
my ( $self, undef, $size ) = @_; # Name unused |
1399
|
2
|
|
|
|
|
3
|
my $syms = '.'; |
1400
|
2
|
|
|
|
|
4
|
my $topo = ''; |
1401
|
2
|
|
|
|
|
4
|
my $letter = 'A'; |
1402
|
2
|
|
|
|
|
8
|
for (my $row = 0; $row < $size; $row++) { |
1403
|
13
|
|
|
|
|
17
|
$syms .= " @{[$letter++]}"; |
|
13
|
|
|
|
|
28
|
|
1404
|
13
|
|
|
|
|
24
|
for (my $col = 0; $col < $size; $col++) { |
1405
|
97
|
|
|
|
|
176
|
$topo .= sprintf ' r%d,c%d', $row, $col; |
1406
|
|
|
|
|
|
|
} |
1407
|
|
|
|
|
|
|
} |
1408
|
2
|
|
|
|
|
5
|
substr ($topo, 0, 1, ''); |
1409
|
2
|
|
|
|
|
7
|
$self->set (columns => $size, rows => $size, symbols => $syms, |
1410
|
|
|
|
|
|
|
topology => $topo); |
1411
|
2
|
|
|
|
|
5
|
return; |
1412
|
|
|
|
|
|
|
} |
1413
|
|
|
|
|
|
|
|
1414
|
|
|
|
|
|
|
sub _set_null { |
1415
|
|
|
|
|
|
|
## my ( $self, $name, $value ) = @_; |
1416
|
0
|
|
|
0
|
|
0
|
my ( $self, undef, $value ) = @_; # Name unused |
1417
|
0
|
0
|
|
|
|
0
|
my ($size, $columns, $rows) = ref $value ? @$value : split ',', $value; |
1418
|
0
|
|
|
|
|
0
|
$self->{cell} = []; # The cells themselves. |
1419
|
0
|
|
|
|
|
0
|
$self->{set} = {}; # The sets themselves. |
1420
|
0
|
|
|
|
|
0
|
$self->{largest_set} = 0; |
1421
|
0
|
|
|
|
|
0
|
$self->{intersection} = {}; |
1422
|
0
|
|
|
|
|
0
|
$self->{cells_unused} = $size; |
1423
|
0
|
|
|
|
|
0
|
foreach my $cell_inx (0 .. $size - 1) { |
1424
|
0
|
|
|
|
|
0
|
my $cell = {membership => [], index => $cell_inx}; |
1425
|
0
|
|
|
|
|
0
|
push @{$self->{cell}}, $cell; |
|
0
|
|
|
|
|
0
|
|
1426
|
|
|
|
|
|
|
} |
1427
|
0
|
|
|
|
|
0
|
delete $self->{backtrack_stack}; # Force setting of new problem. |
1428
|
0
|
0
|
|
|
|
0
|
defined $columns and $self->set (columns => $columns); |
1429
|
0
|
0
|
|
|
|
0
|
defined $rows and $self->set (rows => $rows); |
1430
|
0
|
|
|
|
|
0
|
return; |
1431
|
|
|
|
|
|
|
} |
1432
|
|
|
|
|
|
|
|
1433
|
|
|
|
|
|
|
sub _set_number { |
1434
|
23
|
|
|
23
|
|
43
|
my ( $self, $name, $value ) = @_; |
1435
|
23
|
50
|
|
|
|
53
|
_looks_like_number ($value) or croak <
|
1436
|
|
|
|
|
|
|
Error - Attribute $name must be numeric. |
1437
|
|
|
|
|
|
|
eod |
1438
|
23
|
|
|
|
|
56
|
$self->{$name} = $value; |
1439
|
23
|
|
|
|
|
55
|
return; |
1440
|
|
|
|
|
|
|
} |
1441
|
|
|
|
|
|
|
|
1442
|
|
|
|
|
|
|
sub _set_quincunx { |
1443
|
|
|
|
|
|
|
## my ( $self, $name, $value ) = @_; |
1444
|
0
|
|
|
0
|
|
0
|
my ( $self, undef, $value ) = @_; # Name unused |
1445
|
0
|
0
|
|
|
|
0
|
my ($order, $gap) = ref $value ? @$value : split ',', $value; |
1446
|
0
|
0
|
|
|
|
0
|
$order =~ m/\D/ and croak <
|
1447
|
|
|
|
|
|
|
Error - The quincunx order must be an integer. |
1448
|
|
|
|
|
|
|
eod |
1449
|
0
|
0
|
|
|
|
0
|
if (defined $gap) { |
1450
|
0
|
0
|
|
|
|
0
|
$gap =~ m/\D/ and croak <
|
1451
|
|
|
|
|
|
|
Error - The quincunx gap must be an integer. |
1452
|
|
|
|
|
|
|
eod |
1453
|
0
|
0
|
|
|
|
0
|
$gap > $order - 2 and croak <
|
1454
|
|
|
|
|
|
|
Error - The quincunx gap must not be greater than the order ($order) - 2. |
1455
|
|
|
|
|
|
|
eod |
1456
|
0
|
0
|
|
|
|
0
|
$gap % 2 == $order % 2 or croak <
|
1457
|
|
|
|
|
|
|
Error - The gap must be the same parity (odd or even) as the order. |
1458
|
|
|
|
|
|
|
eod |
1459
|
|
|
|
|
|
|
} else { |
1460
|
0
|
|
|
|
|
0
|
$gap = $order % 2; |
1461
|
|
|
|
|
|
|
} |
1462
|
0
|
|
|
|
|
0
|
my $cols = ($order * 2 + $gap) * $order; |
1463
|
0
|
|
|
|
|
0
|
$self->set(null => [$cols * $cols, $cols, $cols]); |
1464
|
0
|
|
|
|
|
0
|
my $osq = $order * $order; |
1465
|
0
|
|
|
|
|
0
|
$self->set(symbols => join (' ', '.', 1 .. $osq)); |
1466
|
0
|
|
|
|
|
0
|
my @squares = do { # Squares in terms of index of top left corner |
1467
|
0
|
|
|
|
|
0
|
my $offset = ($order + $gap) * $order; |
1468
|
0
|
|
|
|
|
0
|
my $inset = ($order - ($order - $gap) / 2) * $order; |
1469
|
|
|
|
|
|
|
( |
1470
|
0
|
|
|
|
|
0
|
0, # Top left square |
1471
|
|
|
|
|
|
|
$offset, # Top right square |
1472
|
|
|
|
|
|
|
$inset * $cols + $inset, # Middle square |
1473
|
|
|
|
|
|
|
$offset * $cols, # Bottom left square |
1474
|
|
|
|
|
|
|
$offset * ($cols + 1), # Bottom right square |
1475
|
|
|
|
|
|
|
) |
1476
|
|
|
|
|
|
|
}; |
1477
|
0
|
|
|
|
|
0
|
my $limit = $osq - 1; |
1478
|
0
|
|
|
|
|
0
|
my @colinx = map {$_ * $cols} 0 .. $limit; |
|
0
|
|
|
|
|
0
|
|
1479
|
0
|
|
|
|
|
0
|
my @sqinx = map {$_ .. $_ + $order - 1} map {$_ * $cols} 0 .. $order - 1; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1480
|
0
|
|
|
|
|
0
|
my @sqloc = map {$_ * $order} @sqinx; |
|
0
|
|
|
|
|
0
|
|
1481
|
0
|
|
|
|
|
0
|
my @sqgened; # 's' sets generated, by origin cell. |
1482
|
|
|
|
|
|
|
# Crete the row, column, and square sets. These have the same names |
1483
|
|
|
|
|
|
|
# as those created by the corresponding 'sudoku' topology, but with |
1484
|
|
|
|
|
|
|
# 'g0' .. 'g4' prepended, representing the five individual |
1485
|
|
|
|
|
|
|
# 'standard' sudoku grids. For topology 'quincunx 3', the top left |
1486
|
|
|
|
|
|
|
# cell is in sets g0c0,g0r0,g0s0, the top right in g1c8,g1r0,g1s2, |
1487
|
|
|
|
|
|
|
# and so on. Because some of the 's' sets are duplicates, the |
1488
|
|
|
|
|
|
|
# higher-numbered ones are supressed. In topology 'quincunx 3', set |
1489
|
|
|
|
|
|
|
# g0s8 is the same as g2s0, so the latter is supressed. |
1490
|
0
|
|
|
|
|
0
|
foreach my $grid (0 .. $#squares) { |
1491
|
0
|
|
|
|
|
0
|
my $sqr = $squares[$grid]; |
1492
|
0
|
|
|
|
|
0
|
foreach my $inx (0 .. $limit) { |
1493
|
0
|
|
|
|
|
0
|
my $offset = $inx * $cols; |
1494
|
0
|
|
|
|
|
0
|
my $o1 = $offset + $sqr; |
1495
|
0
|
|
|
|
|
0
|
$self->add_set("g${grid}r$inx" => $o1 .. $o1 + $limit); |
1496
|
0
|
|
|
|
|
0
|
$self->add_set("g${grid}c$inx" => map {$_ + $inx + $sqr} |
|
0
|
|
|
|
|
0
|
|
1497
|
|
|
|
|
|
|
@colinx); |
1498
|
0
|
|
|
|
|
0
|
$o1 = $sqloc[$inx] + $sqr; |
1499
|
|
|
|
|
|
|
$sqgened[$o1]++ |
1500
|
0
|
0
|
|
|
|
0
|
or $self->add_set("g${grid}s$inx" => map {$_ + $o1} |
|
0
|
|
|
|
|
0
|
|
1501
|
|
|
|
|
|
|
@sqinx); |
1502
|
|
|
|
|
|
|
} |
1503
|
|
|
|
|
|
|
} |
1504
|
0
|
|
|
|
|
0
|
return; |
1505
|
|
|
|
|
|
|
} |
1506
|
|
|
|
|
|
|
|
1507
|
|
|
|
|
|
|
sub _set_status_value { |
1508
|
21
|
|
|
21
|
|
56
|
my ( $self, $name, $value ) = @_; |
1509
|
21
|
50
|
|
|
|
60
|
_looks_like_number ($value) or croak <
|
1510
|
|
|
|
|
|
|
Error - Attribute $name must be numeric. |
1511
|
|
|
|
|
|
|
eod |
1512
|
21
|
50
|
33
|
|
|
126
|
($value < 0 || $value >= @status_values) and croak <
|
1513
|
|
|
|
|
|
|
Error - Attribute $name must be greater than or equal to 0 and |
1514
|
0
|
|
|
|
|
0
|
less than @{[scalar @status_values]} |
1515
|
|
|
|
|
|
|
eod |
1516
|
21
|
|
|
|
|
49
|
$self->{status_value} = $value; |
1517
|
21
|
|
|
|
|
52
|
$self->{status_text} = $status_values[$value]; |
1518
|
21
|
|
|
|
|
51
|
return; |
1519
|
|
|
|
|
|
|
} |
1520
|
|
|
|
|
|
|
|
1521
|
|
|
|
|
|
|
sub _set_sudoku { |
1522
|
|
|
|
|
|
|
## my ( $self, $name, $order ) = @_; |
1523
|
5
|
|
|
5
|
|
16
|
my ( $self, undef, $order ) = @_; # Name unused |
1524
|
5
|
|
|
|
|
25
|
$self->set( brick => [ $order, $order ] ); |
1525
|
5
|
|
|
|
|
11
|
return; |
1526
|
|
|
|
|
|
|
} |
1527
|
|
|
|
|
|
|
|
1528
|
|
|
|
|
|
|
sub _set_sudokux { |
1529
|
|
|
|
|
|
|
## my ( $self, $name, $order ) = @_; |
1530
|
1
|
|
|
1
|
|
3
|
my ( $self, undef, $order ) = @_; # Name unused |
1531
|
1
|
|
|
|
|
5
|
$self->set (sudoku => $order); |
1532
|
1
|
|
|
|
|
3
|
my $size = $order * $order; |
1533
|
1
|
|
|
|
|
3
|
my $size_minus_1 = $size - 1; |
1534
|
1
|
|
|
|
|
3
|
my $size_plus_1 = $size + 1; |
1535
|
1
|
|
|
|
|
4
|
$self->add_set (d0 => map {$_ * $size_plus_1} 0 .. $size_minus_1); |
|
9
|
|
|
|
|
17
|
|
1536
|
1
|
|
|
|
|
4
|
$self->add_set (d1 => map {$_ * $size_minus_1} 1 .. $size); |
|
9
|
|
|
|
|
15
|
|
1537
|
1
|
|
|
|
|
3
|
return; |
1538
|
|
|
|
|
|
|
} |
1539
|
|
|
|
|
|
|
|
1540
|
|
|
|
|
|
|
sub _set_symbols { |
1541
|
|
|
|
|
|
|
## my ( $self, $name, $value ) = @_; |
1542
|
13
|
|
|
13
|
|
35
|
my ( $self, undef, $value ) = @_; # Name unused |
1543
|
13
|
|
|
|
|
140
|
my @lst = split '\s+', $value; |
1544
|
13
|
|
|
|
|
23
|
my %hsh; |
1545
|
13
|
|
|
|
|
20
|
my $inx = 0; |
1546
|
13
|
|
|
|
|
22
|
my $maxlen = 0; |
1547
|
13
|
|
|
|
|
30
|
foreach (@lst) { |
1548
|
142
|
50
|
|
|
|
208
|
defined $_ or next; |
1549
|
142
|
50
|
|
|
|
228
|
m/,/ and croak <
|
1550
|
|
|
|
|
|
|
Error - Symbols may not contain commas. |
1551
|
|
|
|
|
|
|
eod |
1552
|
142
|
50
|
|
|
|
206
|
exists $hsh{$_} and croak <
|
1553
|
|
|
|
|
|
|
Error - Symbol '$_' specified more than once. |
1554
|
|
|
|
|
|
|
eod |
1555
|
142
|
|
|
|
|
253
|
$hsh{$_} = $inx++; |
1556
|
142
|
|
|
|
|
241
|
$maxlen = max ($maxlen, length ($_)); |
1557
|
|
|
|
|
|
|
} |
1558
|
13
|
|
|
|
|
53
|
$self->{symbol_list} = \@lst; |
1559
|
13
|
|
|
|
|
46
|
$self->{symbol_hash} = \%hsh; |
1560
|
13
|
|
|
|
|
29
|
$self->{symbol_number} = scalar @lst; |
1561
|
13
|
|
|
|
|
32
|
$self->{biggest_spec} = $self->{biggest_symbol} = $maxlen; |
1562
|
13
|
|
|
|
|
37
|
$self->{allowed_symbols} = {}; |
1563
|
13
|
|
|
|
|
34
|
return; |
1564
|
|
|
|
|
|
|
} |
1565
|
|
|
|
|
|
|
|
1566
|
|
|
|
|
|
|
sub _set_topology { |
1567
|
|
|
|
|
|
|
## my ( $self, $name, @args ) = @_; |
1568
|
11
|
|
|
11
|
|
28
|
my ( $self, undef, @args ) = @_; # Name unused |
1569
|
11
|
|
|
|
|
988
|
$self->{cell} = []; # The cells themselves. |
1570
|
11
|
|
|
|
|
361
|
$self->{set} = {}; # The sets themselves. |
1571
|
11
|
|
|
|
|
24
|
$self->{largest_set} = 0; |
1572
|
11
|
|
|
|
|
496
|
$self->{intersection} = {}; |
1573
|
11
|
|
|
|
|
23
|
$self->{cells_unused} = 0; |
1574
|
11
|
|
|
|
|
18
|
my $cell_inx = 0; |
1575
|
11
|
|
|
|
|
32
|
foreach my $cell_def (map {split '\s+', $_} @args) { |
|
11
|
|
|
|
|
360
|
|
1576
|
938
|
|
|
|
|
1707
|
my $cell = {membership => [], index => $cell_inx}; |
1577
|
938
|
|
|
|
|
1084
|
push @{$self->{cell}}, $cell; |
|
938
|
|
|
|
|
1310
|
|
1578
|
938
|
|
|
|
|
1731
|
foreach my $name (sort grep {$_ ne ''} split ',', $cell_def) { |
|
2717
|
|
|
|
|
4775
|
|
1579
|
2717
|
|
|
|
|
3009
|
foreach my $other (@{$cell->{membership}}) { |
|
2717
|
|
|
|
|
3640
|
|
1580
|
2620
|
|
|
|
|
3421
|
my $int = "$other,$name"; |
1581
|
2620
|
|
100
|
|
|
7975
|
$self->{intersection}{$int} ||= []; |
1582
|
2620
|
|
|
|
|
3243
|
push @{$self->{intersection}{$int}}, $cell_inx; |
|
2620
|
|
|
|
|
4354
|
|
1583
|
|
|
|
|
|
|
} |
1584
|
2717
|
|
|
|
|
2915
|
push @{$cell->{membership}}, $name; |
|
2717
|
|
|
|
|
4076
|
|
1585
|
2717
|
|
100
|
|
|
5019
|
my $set = $self->{set}{$name} ||= |
1586
|
|
|
|
|
|
|
{name => $name, membership => []}; |
1587
|
2717
|
|
|
|
|
2870
|
push @{$set->{membership}}, $cell_inx; |
|
2717
|
|
|
|
|
5173
|
|
1588
|
|
|
|
|
|
|
$self->{largest_set} = max ($self->{largest_set}, |
1589
|
2717
|
|
|
|
|
3158
|
scalar @{$set->{membership}}); |
|
2717
|
|
|
|
|
5357
|
|
1590
|
|
|
|
|
|
|
} |
1591
|
938
|
50
|
|
|
|
1206
|
@{$cell->{membership}} or $self->{cells_unused}++; |
|
938
|
|
|
|
|
1522
|
|
1592
|
938
|
|
|
|
|
1260
|
$cell_inx++; |
1593
|
|
|
|
|
|
|
} |
1594
|
11
|
|
|
|
|
335
|
delete $self->{backtrack_stack}; # Force setting of new problem. |
1595
|
11
|
|
|
|
|
44
|
return; |
1596
|
|
|
|
|
|
|
} |
1597
|
|
|
|
|
|
|
|
1598
|
1
|
|
|
1
|
|
2
|
sub _set_value {$_[0]->{$_[1]} = $_[2]; return;} |
|
1
|
|
|
|
|
3
|
|
1599
|
|
|
|
|
|
|
|
1600
|
|
|
|
|
|
|
=head2 solution |
1601
|
|
|
|
|
|
|
|
1602
|
|
|
|
|
|
|
$string = $su->solution(); |
1603
|
|
|
|
|
|
|
|
1604
|
|
|
|
|
|
|
This method returns the next solution to the problem, or undef if there |
1605
|
|
|
|
|
|
|
are no further solutions. The solution is a blank-delimited list of the |
1606
|
|
|
|
|
|
|
symbols each cell contains, with line breaks as specified by the |
1607
|
|
|
|
|
|
|
'columns' attribute. If the problem() method has not been called, |
1608
|
|
|
|
|
|
|
an exception is thrown. |
1609
|
|
|
|
|
|
|
|
1610
|
|
|
|
|
|
|
Status values set: |
1611
|
|
|
|
|
|
|
|
1612
|
|
|
|
|
|
|
SUDOKU_SUCCESS |
1613
|
|
|
|
|
|
|
SUDOKU_NO_SOLUTION |
1614
|
|
|
|
|
|
|
SUDOKU_TOO_HARD |
1615
|
|
|
|
|
|
|
|
1616
|
|
|
|
|
|
|
=cut |
1617
|
|
|
|
|
|
|
|
1618
|
|
|
|
|
|
|
sub solution { |
1619
|
19
|
|
|
19
|
1
|
46
|
my ( $self ) = @_; |
1620
|
|
|
|
|
|
|
|
1621
|
19
|
50
|
|
|
|
50
|
$self->{backtrack_stack} or croak <
|
1622
|
|
|
|
|
|
|
Error - You cannot call the solution() method unless you have specified |
1623
|
|
|
|
|
|
|
the problem via the problem() method. |
1624
|
|
|
|
|
|
|
eod |
1625
|
|
|
|
|
|
|
|
1626
|
19
|
50
|
|
|
|
43
|
$self->{debug} and print <
|
1627
|
|
|
|
|
|
|
Debug solution - entering method. Stack depth = @{[ |
1628
|
0
|
|
|
|
|
0
|
scalar @{$self->{backtrack_stack}}]} |
|
0
|
|
|
|
|
0
|
|
1629
|
|
|
|
|
|
|
eod |
1630
|
|
|
|
|
|
|
|
1631
|
19
|
|
|
|
|
43
|
return $self->_constrain (); |
1632
|
|
|
|
|
|
|
} |
1633
|
|
|
|
|
|
|
|
1634
|
|
|
|
|
|
|
=head2 steps |
1635
|
|
|
|
|
|
|
|
1636
|
|
|
|
|
|
|
$string = $su->steps(); |
1637
|
|
|
|
|
|
|
|
1638
|
|
|
|
|
|
|
=for comment help syntax-highlighting editor " |
1639
|
|
|
|
|
|
|
|
1640
|
|
|
|
|
|
|
This method returns the steps taken to solve the problem. If no |
1641
|
|
|
|
|
|
|
solution was found, it returns the steps taken to determine this. If |
1642
|
|
|
|
|
|
|
called in list context, you get an actual copy of the list. The first |
1643
|
|
|
|
|
|
|
element is the name of the constraint applied: |
1644
|
|
|
|
|
|
|
|
1645
|
|
|
|
|
|
|
F = forced: only one value works in this cell; |
1646
|
|
|
|
|
|
|
N = numeration or necessary: this is the only cell |
1647
|
|
|
|
|
|
|
that can supply the given value; |
1648
|
|
|
|
|
|
|
B = box claim: if a candidate number appears in only |
1649
|
|
|
|
|
|
|
one row or column of a given box, it can be |
1650
|
|
|
|
|
|
|
eliminated as a candidate in that row or column |
1651
|
|
|
|
|
|
|
but outside that box; |
1652
|
|
|
|
|
|
|
T = tuple, which is a generalization of the concept |
1653
|
|
|
|
|
|
|
pair, triple, and so on. These come in two |
1654
|
|
|
|
|
|
|
varieties for a given size of the tuple N: |
1655
|
|
|
|
|
|
|
naked: N cells contain among them N values, so |
1656
|
|
|
|
|
|
|
no cells outside the tuple can supply those |
1657
|
|
|
|
|
|
|
values. |
1658
|
|
|
|
|
|
|
hidden: N cells contain N values which do not |
1659
|
|
|
|
|
|
|
occur outside those cells, so any other values |
1660
|
|
|
|
|
|
|
in the tuple are supressed. |
1661
|
|
|
|
|
|
|
? = no constraint: generated in backtrack mode. |
1662
|
|
|
|
|
|
|
|
1663
|
|
|
|
|
|
|
See C and |
1664
|
|
|
|
|
|
|
L for fuller |
1665
|
|
|
|
|
|
|
definitions of the constraints and how they are applied. The |
1666
|
|
|
|
|
|
|
L section addresses why the former |
1667
|
|
|
|
|
|
|
URL is not an actual POD link. |
1668
|
|
|
|
|
|
|
|
1669
|
|
|
|
|
|
|
The second value is the cell number, as defined by the topology |
1670
|
|
|
|
|
|
|
setting. For the 'sudoku' and 'latin' settings, the cells are |
1671
|
|
|
|
|
|
|
numbered from zero, row-by-row. If you did your own topology, the |
1672
|
|
|
|
|
|
|
first cell you defined is 0, the second is 1, and so on. |
1673
|
|
|
|
|
|
|
|
1674
|
|
|
|
|
|
|
The third value is the value assigned to the cell. If returned in |
1675
|
|
|
|
|
|
|
list context, it is the number assigned to the cell's symbol. If |
1676
|
|
|
|
|
|
|
in scalar context, it is the symbol itself. |
1677
|
|
|
|
|
|
|
|
1678
|
|
|
|
|
|
|
=for comment help syntax-highlighting editor " |
1679
|
|
|
|
|
|
|
|
1680
|
|
|
|
|
|
|
=cut |
1681
|
|
|
|
|
|
|
|
1682
|
|
|
|
|
|
|
sub steps { |
1683
|
1
|
|
|
1
|
1
|
2
|
my ( $self ) = @_; |
1684
|
0
|
|
|
|
|
0
|
return wantarray ? (@{$self->{backtrack_stack}}) : |
1685
|
|
|
|
|
|
|
defined wantarray ? |
1686
|
1
|
50
|
|
|
|
4
|
$self->_format_constraint (@{$self->{backtrack_stack}}) : |
|
1
|
50
|
|
|
|
4
|
|
1687
|
|
|
|
|
|
|
undef; |
1688
|
|
|
|
|
|
|
} |
1689
|
|
|
|
|
|
|
|
1690
|
|
|
|
|
|
|
=head2 unload |
1691
|
|
|
|
|
|
|
|
1692
|
|
|
|
|
|
|
$string = $su->unload(); |
1693
|
|
|
|
|
|
|
|
1694
|
|
|
|
|
|
|
This method returns either the current puzzle or the current solution, |
1695
|
|
|
|
|
|
|
depending on whether the solution() method has been called since the |
1696
|
|
|
|
|
|
|
puzzle was loaded. |
1697
|
|
|
|
|
|
|
|
1698
|
|
|
|
|
|
|
=cut |
1699
|
|
|
|
|
|
|
|
1700
|
|
|
|
|
|
|
sub unload { |
1701
|
2
|
|
|
2
|
1
|
5
|
my ( $self ) = @_; |
1702
|
2
|
|
|
|
|
5
|
return $self->_unload () |
1703
|
|
|
|
|
|
|
} |
1704
|
|
|
|
|
|
|
|
1705
|
|
|
|
|
|
|
######################################################################## |
1706
|
|
|
|
|
|
|
|
1707
|
|
|
|
|
|
|
# Private methods and subroutines. |
1708
|
|
|
|
|
|
|
|
1709
|
|
|
|
|
|
|
# $status_value = $su->_constrain (); |
1710
|
|
|
|
|
|
|
|
1711
|
|
|
|
|
|
|
# This method applies all possible constraints to the current |
1712
|
|
|
|
|
|
|
# problem, placing them on the backtrack stack. The backtrack |
1713
|
|
|
|
|
|
|
# algorithm needs to remove these when backtracking. The return |
1714
|
|
|
|
|
|
|
# is false if we ran out of constraints, or true if we found |
1715
|
|
|
|
|
|
|
# a constraint that could not be satisfied. |
1716
|
|
|
|
|
|
|
|
1717
|
|
|
|
|
|
|
my %constraint_method = ( |
1718
|
|
|
|
|
|
|
'?' => '_constraint_backtrack', |
1719
|
|
|
|
|
|
|
); |
1720
|
|
|
|
|
|
|
|
1721
|
|
|
|
|
|
|
sub _constrain { |
1722
|
19
|
|
|
19
|
|
32
|
my ( $self ) = @_; |
1723
|
19
|
|
50
|
|
|
50
|
my $stack = $self->{backtrack_stack} ||= []; # May hit this |
1724
|
|
|
|
|
|
|
# when initializing. |
1725
|
19
|
|
50
|
|
|
44
|
my $used = $self->{constraints_used} ||= {}; |
1726
|
19
|
|
|
|
|
25
|
my $iterations; |
1727
|
|
|
|
|
|
|
$iterations = $self->{iteration_limit} |
1728
|
19
|
50
|
|
|
|
45
|
if $self->{iteration_limit} > 0; |
1729
|
|
|
|
|
|
|
|
1730
|
|
|
|
|
|
|
$self->{no_more_solutions} and |
1731
|
19
|
50
|
|
|
|
41
|
return $self->_unload (undef, SUDOKU_NO_SOLUTION); |
1732
|
|
|
|
|
|
|
|
1733
|
19
|
100
|
|
|
|
27
|
@{$self->{backtrack_stack}} and do { |
|
19
|
|
|
|
|
37
|
|
1734
|
1
|
50
|
|
|
|
4
|
$self->_constraint_remove and |
1735
|
|
|
|
|
|
|
return $self->_unload (undef, SUDOKU_NO_SOLUTION); |
1736
|
|
|
|
|
|
|
}; |
1737
|
|
|
|
|
|
|
|
1738
|
18
|
50
|
|
|
|
39
|
$self->{cells_unassigned} or do { |
1739
|
0
|
|
|
|
|
0
|
$self->{no_more_solutions} = 1; |
1740
|
0
|
|
|
|
|
0
|
return $self->_unload ('', SUDOKU_SUCCESS); |
1741
|
|
|
|
|
|
|
}; |
1742
|
|
|
|
|
|
|
|
1743
|
18
|
|
|
|
|
32
|
my $number_of_cells = @{$self->{cell}}; |
|
18
|
|
|
|
|
27
|
|
1744
|
|
|
|
|
|
|
|
1745
|
|
|
|
|
|
|
constraint_loop: |
1746
|
|
|
|
|
|
|
{ # Begin outer constraint loop. |
1747
|
|
|
|
|
|
|
|
1748
|
18
|
|
|
|
|
25
|
foreach my $constraint (qw{F N B T ?}) { |
|
356
|
|
|
|
|
593
|
|
1749
|
685
|
50
|
|
|
|
789
|
confess <{cell}} != $number_of_cells; |
|
685
|
|
|
|
|
1346
|
|
1750
|
|
|
|
|
|
|
Programming error - Before trying $constraint constraint. |
1751
|
|
|
|
|
|
|
We started with $number_of_cells cells, but now have @{[ |
1752
|
0
|
|
|
|
|
0
|
scalar @{$self->{cell}}]}. |
|
0
|
|
|
|
|
0
|
|
1753
|
|
|
|
|
|
|
eod |
1754
|
685
|
|
33
|
|
|
2138
|
my $method = $constraint_method{$constraint} || |
1755
|
|
|
|
|
|
|
"_constraint_$constraint"; |
1756
|
685
|
50
|
|
|
|
1714
|
my $rslt = $self->$method () or next; |
1757
|
685
|
100
|
|
|
|
1344
|
@$rslt or next; |
1758
|
356
|
|
|
|
|
530
|
foreach my $constr (@$rslt) { |
1759
|
1149
|
50
|
|
|
|
1647
|
if (ref $constr) { |
1760
|
1149
|
|
|
|
|
1529
|
push @$stack, $constr; |
1761
|
1149
|
|
|
|
|
1701
|
$used->{$constr->[0]}++ |
1762
|
|
|
|
|
|
|
} else { |
1763
|
0
|
0
|
|
|
|
0
|
my $rslt = $self->_constraint_remove or |
1764
|
|
|
|
|
|
|
redo constraint_loop; |
1765
|
0
|
|
|
|
|
0
|
return $self->_unload ('', $rslt); |
1766
|
|
|
|
|
|
|
} |
1767
|
|
|
|
|
|
|
} |
1768
|
|
|
|
|
|
|
$self->{cells_unassigned} or |
1769
|
356
|
100
|
|
|
|
703
|
return $self->_unload ('', SUDOKU_SUCCESS); |
1770
|
338
|
|
|
|
|
700
|
redo constraint_loop; |
1771
|
|
|
|
|
|
|
} |
1772
|
|
|
|
|
|
|
|
1773
|
|
|
|
|
|
|
} # end outer constraint loop. |
1774
|
|
|
|
|
|
|
|
1775
|
0
|
|
|
|
|
0
|
$self->set (status_value => SUDOKU_TOO_HARD); |
1776
|
0
|
|
|
|
|
0
|
return; |
1777
|
|
|
|
|
|
|
} |
1778
|
|
|
|
|
|
|
|
1779
|
|
|
|
|
|
|
# Constraint executors: |
1780
|
|
|
|
|
|
|
# These all return a reference to the constraints to be stacked, |
1781
|
|
|
|
|
|
|
# provided progress was made. Otherwise they return 0. At the |
1782
|
|
|
|
|
|
|
# point a contradiction is found, they push 'backtrack' on the |
1783
|
|
|
|
|
|
|
# end of the list to be returned, and return immediately. |
1784
|
|
|
|
|
|
|
|
1785
|
|
|
|
|
|
|
# F constraint - only one value possible. Unlike the other |
1786
|
|
|
|
|
|
|
# constraints, we keep iterating this one until we make no |
1787
|
|
|
|
|
|
|
# progress. |
1788
|
|
|
|
|
|
|
|
1789
|
|
|
|
|
|
|
sub _constraint_F { |
1790
|
356
|
|
|
356
|
|
563
|
my ( $self ) = @_; |
1791
|
356
|
|
|
|
|
464
|
my @stack; |
1792
|
356
|
|
|
|
|
432
|
my $done = 1; |
1793
|
|
|
|
|
|
|
|
1794
|
356
|
|
|
|
|
641
|
while ($done) { |
1795
|
547
|
|
|
|
|
632
|
$done = 0; |
1796
|
547
|
|
|
|
|
660
|
my $inx = 0; # Cell index. |
1797
|
547
|
|
|
|
|
620
|
foreach my $cell (@{$self->{cell}}) { |
|
547
|
|
|
|
|
882
|
|
1798
|
65630
|
100
|
|
|
|
94422
|
next if $cell->{content}; # Skip already-assigned cells. |
1799
|
30499
|
50
|
|
|
|
32243
|
next unless @{$cell->{membership}}; # Skip unused cells. |
|
30499
|
|
|
|
|
45535
|
|
1800
|
30499
|
|
|
|
|
33386
|
my $pos = 0; |
1801
|
30499
|
100
|
|
|
|
32180
|
foreach (values %{$cell->{possible}}) {$_ or $pos++}; |
|
30499
|
|
|
|
|
51903
|
|
|
385548
|
|
|
|
|
539419
|
|
1802
|
30499
|
100
|
|
|
|
41186
|
if ($pos > 1) { # > 1 possibility. Can't apply. |
|
|
50
|
|
|
|
|
|
1803
|
|
|
|
|
|
|
} elsif ($pos == 1) { # Exactly 1 possibility. Apply. |
1804
|
856
|
|
|
|
|
952
|
my $val; |
1805
|
856
|
|
|
|
|
921
|
foreach (keys %{$cell->{possible}}) { |
|
856
|
|
|
|
|
2338
|
|
1806
|
4582
|
100
|
|
|
|
7032
|
next if $cell->{possible}{$_}; |
1807
|
856
|
|
|
|
|
1019
|
$val = $_; |
1808
|
856
|
|
|
|
|
945
|
last; |
1809
|
|
|
|
|
|
|
} |
1810
|
856
|
50
|
|
|
|
1781
|
$self->_try ($cell, $val) and confess <
|
1811
|
|
|
|
|
|
|
Programming error - Passed 'F' constraint but _try failed. |
1812
|
|
|
|
|
|
|
eod |
1813
|
856
|
|
|
|
|
1708
|
my $constraint = [F => [$inx, $val]]; |
1814
|
|
|
|
|
|
|
$self->{debug} and |
1815
|
856
|
50
|
|
|
|
1455
|
print '# ', $self->_format_constraint ($constraint); |
1816
|
856
|
|
|
|
|
986
|
$done++; |
1817
|
856
|
|
|
|
|
1284
|
push @stack, $constraint; |
1818
|
856
|
100
|
|
|
|
1498
|
$self->{cells_unassigned} or do {$done = 0; last}; |
|
18
|
|
|
|
|
22
|
|
|
18
|
|
|
|
|
41
|
|
1819
|
|
|
|
|
|
|
} else { # No possibilities. Backtrack. |
1820
|
0
|
0
|
|
|
|
0
|
$self->{debug} and print <
|
1821
|
|
|
|
|
|
|
Debug - Cell $inx has no possible values. Backtracking. |
1822
|
|
|
|
|
|
|
eod |
1823
|
0
|
0
|
|
|
|
0
|
$self->{debug} > 1 and do { |
1824
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Terse = 1; |
1825
|
0
|
|
|
|
|
0
|
print Dumper $cell; |
1826
|
|
|
|
|
|
|
}; |
1827
|
0
|
|
|
|
|
0
|
push @stack, 'backtrack'; |
1828
|
0
|
|
|
|
|
0
|
$done = 0; |
1829
|
0
|
|
|
|
|
0
|
last; |
1830
|
|
|
|
|
|
|
} |
1831
|
|
|
|
|
|
|
} continue { |
1832
|
65612
|
|
|
|
|
79445
|
$inx++; |
1833
|
|
|
|
|
|
|
} |
1834
|
|
|
|
|
|
|
} |
1835
|
356
|
|
|
|
|
1028
|
return \@stack; |
1836
|
|
|
|
|
|
|
} |
1837
|
|
|
|
|
|
|
|
1838
|
|
|
|
|
|
|
# N constraint - the only cell which supplies a necessary value. |
1839
|
|
|
|
|
|
|
|
1840
|
|
|
|
|
|
|
sub _constraint_N { |
1841
|
293
|
|
|
293
|
|
528
|
my ( $self ) = @_; |
1842
|
293
|
|
|
|
|
370
|
while (my ($name, $set) = each %{$self->{set}}) { |
|
4062
|
|
|
|
|
9680
|
|
1843
|
4032
|
|
|
|
|
4615
|
my @suppliers; |
1844
|
4032
|
|
|
|
|
4582
|
foreach my $inx (@{$set->{membership}}) { |
|
4032
|
|
|
|
|
6494
|
|
1845
|
51063
|
|
|
|
|
60948
|
my $cell = $self->{cell}[$inx]; |
1846
|
51063
|
100
|
|
|
|
76886
|
next if $cell->{content}; |
1847
|
|
|
|
|
|
|
# No need to check @{$cell->{membership}}, since the cell is |
1848
|
|
|
|
|
|
|
# known to be a member of set $name. |
1849
|
26004
|
|
|
|
|
27939
|
while (my ($val, $count) = each %{$cell->{possible}}) { |
|
375887
|
|
|
|
|
677040
|
|
1850
|
349883
|
100
|
|
|
|
516066
|
next if $count; |
1851
|
102657
|
|
100
|
|
|
182638
|
$suppliers[$val] ||= []; |
1852
|
102657
|
|
|
|
|
105963
|
push @{$suppliers[$val]}, $inx; |
|
102657
|
|
|
|
|
171296
|
|
1853
|
|
|
|
|
|
|
} |
1854
|
|
|
|
|
|
|
} |
1855
|
4032
|
|
|
|
|
5120
|
my $limit = @suppliers; |
1856
|
4032
|
|
|
|
|
6931
|
for (my $val = 1; $val < $limit; $val++) { |
1857
|
43333
|
100
|
100
|
|
|
68853
|
next unless $suppliers[$val] && @{$suppliers[$val]} == 1; |
|
25292
|
|
|
|
|
63949
|
|
1858
|
263
|
|
|
|
|
409
|
my $inx = $suppliers[$val][0]; |
1859
|
263
|
0
|
|
|
|
645
|
$self->_try ($inx, $val) and confess <{debug} ? <
|
|
|
50
|
|
|
|
|
|
1860
|
|
|
|
|
|
|
Programming error - Cell $inx passed 'N' constraint but try of |
1861
|
|
|
|
|
|
|
$self->{symbol_list}[$val] failed. |
1862
|
|
|
|
|
|
|
eod |
1863
|
0
|
|
|
|
|
0
|
@{[$self->_unload |
1864
|
|
|
|
|
|
|
]} set: $name |
1865
|
0
|
|
|
|
|
0
|
cell: @{[Dumper ($self->{cell}[$inx])]} |
1866
|
|
|
|
|
|
|
eod |
1867
|
263
|
|
|
|
|
678
|
my $constraint = [N => [$inx, $val]]; |
1868
|
|
|
|
|
|
|
$self->{debug} and |
1869
|
263
|
50
|
|
|
|
519
|
print '# ', $self->_format_constraint ($constraint); |
1870
|
263
|
|
|
|
|
292
|
keys %{$self->{set}}; # Reset iterator. |
|
263
|
|
|
|
|
379
|
|
1871
|
263
|
|
|
|
|
1067
|
return [$constraint]; |
1872
|
|
|
|
|
|
|
} |
1873
|
|
|
|
|
|
|
} |
1874
|
30
|
|
|
|
|
111
|
return []; |
1875
|
|
|
|
|
|
|
} |
1876
|
|
|
|
|
|
|
|
1877
|
|
|
|
|
|
|
# B constraint - "box claim". Given two sets whose intersection |
1878
|
|
|
|
|
|
|
# contains more than one cell, if all cells which can contribute |
1879
|
|
|
|
|
|
|
# a given value to one set are in the intersection, no cell in |
1880
|
|
|
|
|
|
|
# the second set can contribute that value. Note that this |
1881
|
|
|
|
|
|
|
# constraint does NOT actually assign a value to a cell, it just |
1882
|
|
|
|
|
|
|
# eliminates possible values. The name is because on the |
1883
|
|
|
|
|
|
|
# "standard" sudoku layout one of the sets is always a box; the |
1884
|
|
|
|
|
|
|
# other can be a row or a column. |
1885
|
|
|
|
|
|
|
|
1886
|
|
|
|
|
|
|
sub _constraint_B { |
1887
|
30
|
|
|
30
|
|
62
|
my ( $self ) = @_; |
1888
|
30
|
|
|
|
|
42
|
my $done = 0; |
1889
|
30
|
|
|
|
|
64
|
while (my ($int, $cells) = each %{$self->{intersection}}) { |
|
5002
|
|
|
|
|
11530
|
|
1890
|
4996
|
100
|
|
|
|
8524
|
next unless @$cells > 1; |
1891
|
1680
|
|
|
|
|
1930
|
my @int_supplies; # Values supplied by the intersection |
1892
|
|
|
|
|
|
|
my %int_cells; # Cells in the intersection |
1893
|
1680
|
|
|
|
|
2549
|
foreach my $inx (@$cells) { |
1894
|
6404
|
100
|
|
|
|
11312
|
next if $self->{cell}[$inx]{content}; |
1895
|
|
|
|
|
|
|
# No need to check @{$cell->{membership}}, since the cell is |
1896
|
|
|
|
|
|
|
# known to be a member of at least two sets. |
1897
|
3548
|
|
|
|
|
6230
|
$int_cells{$inx} = 1; |
1898
|
3548
|
|
|
|
|
3937
|
while (my ($val, $imposs) = each %{ |
1899
|
57367
|
|
|
|
|
113042
|
$self->{cell}[$inx]{possible}}) { |
1900
|
53819
|
100
|
|
|
|
85566
|
$int_supplies[$val] = 1 unless $imposs; |
1901
|
|
|
|
|
|
|
} |
1902
|
|
|
|
|
|
|
} |
1903
|
1680
|
|
|
|
|
2034
|
my %ext_supplies; # Intersection values also supplied outside. |
1904
|
|
|
|
|
|
|
my %ext_cells; # Cells not in the intersection. |
1905
|
1680
|
|
|
|
|
3756
|
my @set_names = split ',', $int; |
1906
|
1680
|
|
|
|
|
2248
|
foreach my $set (@set_names) { |
1907
|
3360
|
|
|
|
|
5736
|
$ext_supplies{$set} = []; |
1908
|
3360
|
|
|
|
|
4750
|
$ext_cells{$set} = []; |
1909
|
3360
|
|
|
|
|
3875
|
foreach my $inx (@{$self->{set}{$set}{membership}}) { |
|
3360
|
|
|
|
|
6211
|
|
1910
|
49362
|
100
|
|
|
|
72547
|
next if $int_cells{$inx}; # Skip cells in intersection. |
1911
|
42266
|
100
|
|
|
|
70518
|
next if $self->{cell}[$inx]{content}; |
1912
|
20236
|
|
|
|
|
21806
|
push @{$ext_cells{$set}}, $inx; |
|
20236
|
|
|
|
|
33960
|
|
1913
|
20236
|
|
|
|
|
23596
|
while (my ($val, $imposs) = each %{ |
1914
|
332372
|
|
|
|
|
644509
|
$self->{cell}[$inx]{possible}}) { |
1915
|
312136
|
100
|
100
|
|
|
564387
|
$ext_supplies{$set}[$val] = 1 |
1916
|
|
|
|
|
|
|
if !$imposs && $int_supplies[$val]; |
1917
|
|
|
|
|
|
|
} |
1918
|
|
|
|
|
|
|
} |
1919
|
|
|
|
|
|
|
} |
1920
|
1680
|
|
|
|
|
4125
|
for (my $val = 1; $val < @int_supplies; $val++) { |
1921
|
19614
|
100
|
|
|
|
32212
|
next unless $int_supplies[$val]; |
1922
|
8261
|
|
|
|
|
9998
|
my @occurs_in = grep {$ext_supplies{$_}[$val]} @set_names; |
|
16522
|
|
|
|
|
26924
|
|
1923
|
8261
|
100
|
100
|
|
|
31253
|
next unless @occurs_in && @occurs_in < @set_names; |
1924
|
24
|
|
|
|
|
42
|
my %cells_claimed; |
1925
|
24
|
|
|
|
|
63
|
foreach my $set (@occurs_in) { |
1926
|
24
|
|
|
|
|
29
|
foreach my $inx (@{$ext_cells{$set}}) { |
|
24
|
|
|
|
|
57
|
|
1927
|
127
|
100
|
|
|
|
243
|
next if $self->{cell}[$inx]{possible}{$val}; |
1928
|
60
|
|
|
|
|
103
|
$cells_claimed{$inx} = 1; |
1929
|
60
|
|
|
|
|
79
|
$self->{cell}[$inx]{possible}{$val} = 1; |
1930
|
60
|
|
|
|
|
83
|
$done++; |
1931
|
|
|
|
|
|
|
} |
1932
|
|
|
|
|
|
|
} |
1933
|
24
|
50
|
|
|
|
89
|
next unless $done; |
1934
|
24
|
|
|
|
|
256
|
my $constraint = [B => [[sort keys %cells_claimed], $val]]; |
1935
|
|
|
|
|
|
|
$self->{debug} and |
1936
|
24
|
50
|
|
|
|
95
|
print '# ', $self->_format_constraint ($constraint); |
1937
|
24
|
|
|
|
|
42
|
keys %{$self->{intersection}}; # Reset iterator. |
|
24
|
|
|
|
|
52
|
|
1938
|
24
|
|
|
|
|
166
|
return [$constraint]; |
1939
|
|
|
|
|
|
|
} |
1940
|
|
|
|
|
|
|
} |
1941
|
6
|
|
|
|
|
36
|
return [] |
1942
|
|
|
|
|
|
|
} |
1943
|
|
|
|
|
|
|
|
1944
|
|
|
|
|
|
|
# T constraint - "tuple" (double, triple, quad). These come in |
1945
|
|
|
|
|
|
|
# two flavors, "naked" and "hidden". Considering only pairs for |
1946
|
|
|
|
|
|
|
# the moment: |
1947
|
|
|
|
|
|
|
# A "naked pair" is two cells in the same set which contain the same |
1948
|
|
|
|
|
|
|
# pair of possibilities, and only those possibilities. These |
1949
|
|
|
|
|
|
|
# possibilities are then excluded from other cells in the set. |
1950
|
|
|
|
|
|
|
# A "hidden pair" is when there is a pair of values which can only |
1951
|
|
|
|
|
|
|
# be contributed to the set by one or the other of a pair of |
1952
|
|
|
|
|
|
|
# cells. These cells then must supply these values, and any other |
1953
|
|
|
|
|
|
|
# values supplied by cells in the pair can be eliminated. |
1954
|
|
|
|
|
|
|
# For higher groups (triples, quads ...) the rules generalize, except |
1955
|
|
|
|
|
|
|
# that all of the candidate values need not be present in all of |
1956
|
|
|
|
|
|
|
# the cells under consideration; it is only necessary that none |
1957
|
|
|
|
|
|
|
# of the candidate values appears outside the cells under |
1958
|
|
|
|
|
|
|
# consideration. |
1959
|
|
|
|
|
|
|
# |
1960
|
|
|
|
|
|
|
# Glenn Fowler of AT&T (http://www.research.att.com/~gsf/sudoku/) |
1961
|
|
|
|
|
|
|
# lumps all these together. But he refers to Angus Johnson |
1962
|
|
|
|
|
|
|
# (http://www.angusj.com/sudoku/hints.php) for the details, and |
1963
|
|
|
|
|
|
|
# Angus separates naked and hidden tuples. |
1964
|
|
|
|
|
|
|
|
1965
|
|
|
|
|
|
|
sub _constraint_T { |
1966
|
6
|
|
|
6
|
|
15
|
my ( $self ) = @_; |
1967
|
6
|
|
|
|
|
21
|
my @tuple; # Tuple indices |
1968
|
|
|
|
|
|
|
my %vacant; # Empty cells by set. $vacant{$set} = [$cell ...] |
1969
|
6
|
|
|
|
|
0
|
my %contributors; # Number of cells which can contrib value, by set. |
1970
|
6
|
|
|
|
|
11
|
my $syms = @{$self->{symbol_list}}; |
|
6
|
|
|
|
|
16
|
|
1971
|
|
|
|
|
|
|
|
1972
|
6
|
|
|
|
|
11
|
while (my ($name, $set) = each %{$self->{set}}) { |
|
233
|
|
|
|
|
603
|
|
1973
|
3051
|
|
|
|
|
4607
|
my @open = grep {!$_->{content}} |
1974
|
227
|
100
|
|
|
|
257
|
map {$self->{cell}[$_]} @{$set->{membership}} |
|
3051
|
|
|
|
|
3773
|
|
|
227
|
|
|
|
|
335
|
|
1975
|
|
|
|
|
|
|
or next; |
1976
|
|
|
|
|
|
|
# No need to check @{$_->{membership}} in the grep, since cell |
1977
|
|
|
|
|
|
|
# $_ is known to be a member of set $name. |
1978
|
214
|
|
|
|
|
392
|
foreach my $cell (@open) { |
1979
|
1614
|
|
|
|
|
2382
|
for (my $val = 1; $val < $syms; $val++) { |
1980
|
23556
|
100
|
|
|
|
40523
|
$cell->{possible}{$val} and next; |
1981
|
6344
|
|
100
|
|
|
9043
|
$contributors{$name} ||= []; |
1982
|
6344
|
|
|
|
|
9555
|
$contributors{$name}[$val]++; |
1983
|
|
|
|
|
|
|
} |
1984
|
|
|
|
|
|
|
} |
1985
|
214
|
100
|
|
|
|
260
|
@{$contributors{$name}} = map {$_ || 0} @{$contributors{$name}}; |
|
214
|
|
|
|
|
398
|
|
|
2912
|
|
|
|
|
4879
|
|
|
214
|
|
|
|
|
340
|
|
1986
|
214
|
|
|
|
|
400
|
$vacant{$name} = \@open; |
1987
|
214
|
|
100
|
|
|
534
|
$tuple[scalar @open] ||= [map {[$_]} 0 .. $#open]; |
|
332
|
|
|
|
|
632
|
|
1988
|
|
|
|
|
|
|
} |
1989
|
|
|
|
|
|
|
|
1990
|
6
|
|
|
|
|
29
|
for (my $order = 2; $order <= $self->{max_tuple}; $order++) { |
1991
|
6
|
|
|
|
|
22
|
for (my $inx = 1; $inx < @tuple; $inx++) { |
1992
|
61
|
100
|
|
|
|
111
|
next unless $tuple[$inx]; |
1993
|
45
|
|
|
|
|
61
|
my $max = $inx - 1; |
1994
|
287
|
|
|
|
|
393
|
$tuple[$inx] = [map {my @tpl = @$_; |
1995
|
287
|
|
|
|
|
386
|
map {[@tpl, $_]} $tpl[-1] + 1 .. $max} |
|
1327
|
|
|
|
|
2252
|
|
1996
|
45
|
|
|
|
|
55
|
grep {$_->[-1] < $max} @{$tuple[$inx]}]; |
|
332
|
|
|
|
|
449
|
|
|
45
|
|
|
|
|
78
|
|
1997
|
45
|
50
|
|
|
|
122
|
$tuple[$inx] = undef unless @{$tuple[$inx]}; |
|
45
|
|
|
|
|
122
|
|
1998
|
|
|
|
|
|
|
} |
1999
|
|
|
|
|
|
|
|
2000
|
|
|
|
|
|
|
# Okay, I have generated the blasted tuples. Now I need to take |
2001
|
|
|
|
|
|
|
# the union of all values provided by the tuple of cells. If the |
2002
|
|
|
|
|
|
|
# number of values in this union is equal to the current order, I |
2003
|
|
|
|
|
|
|
# have potentially found a naked tuple, and if this lets me |
2004
|
|
|
|
|
|
|
# eliminate any values outside the tuple I can apply the |
2005
|
|
|
|
|
|
|
# constraint. If the number of values inside the union is greater |
2006
|
|
|
|
|
|
|
# than the current order, I need to consider whether any tuple of |
2007
|
|
|
|
|
|
|
# supplied values is not represented outside the cell tuple; if |
2008
|
|
|
|
|
|
|
# so, I have a hidden tuple and can eliminate the superfluous |
2009
|
|
|
|
|
|
|
# values. |
2010
|
|
|
|
|
|
|
|
2011
|
6
|
|
|
|
|
49
|
foreach my $name (keys %vacant) { |
2012
|
49
|
|
|
|
|
72
|
my $open = $vacant{$name}; |
2013
|
49
|
50
|
|
|
|
91
|
next unless $tuple[@$open]; |
2014
|
49
|
|
|
|
|
60
|
my $contributed = $contributors{$name}; |
2015
|
49
|
|
|
|
|
57
|
foreach my $tuple (@{$tuple[@$open]}) { |
|
49
|
|
|
|
|
84
|
|
2016
|
998
|
|
|
|
|
1117
|
my @tcontr; # number of times each value |
2017
|
|
|
|
|
|
|
# contributed by the tuple. |
2018
|
998
|
|
|
|
|
1305
|
foreach my $inx (@$tuple) { |
2019
|
1996
|
|
|
|
|
2404
|
my $cell = $open->[$inx]; |
2020
|
1996
|
|
|
|
|
2969
|
for (my $val = 1; $val < $syms; $val++) { |
2021
|
29990
|
100
|
|
|
|
50683
|
next if $cell->{possible}{$val}; |
2022
|
7803
|
|
|
|
|
11792
|
$tcontr[$val]++; |
2023
|
|
|
|
|
|
|
} |
2024
|
|
|
|
|
|
|
} |
2025
|
998
|
100
|
|
|
|
1335
|
@tcontr = map {$_ || 0} @tcontr; |
|
14866
|
|
|
|
|
25182
|
|
2026
|
|
|
|
|
|
|
|
2027
|
|
|
|
|
|
|
# At this point, @tcontr contains how many cells in the tuple |
2028
|
|
|
|
|
|
|
# contribute each value. Calculate the number of discrete values |
2029
|
|
|
|
|
|
|
# the tuple can contribute. |
2030
|
|
|
|
|
|
|
|
2031
|
|
|
|
|
|
|
# If the number of discrete values contributed by the tuple is |
2032
|
|
|
|
|
|
|
# equal to the current order, we have a naked tuple. We have an |
2033
|
|
|
|
|
|
|
# "effective" naked tuple if at least one of the values |
2034
|
|
|
|
|
|
|
# contributed by the tuple occurs outside the tuple. We can |
2035
|
|
|
|
|
|
|
# determine this by subtracting the values in @tcontr from the |
2036
|
|
|
|
|
|
|
# corresponding values in @$contributed; if we get a positive |
2037
|
|
|
|
|
|
|
# result for any cell, we have an "effective" naked tuple. |
2038
|
|
|
|
|
|
|
|
2039
|
998
|
|
|
|
|
1387
|
my $discrete = grep {$_} @tcontr; |
|
14866
|
|
|
|
|
16395
|
|
2040
|
998
|
|
|
|
|
1171
|
my $constraint; |
2041
|
|
|
|
|
|
|
my @tuple_member; |
2042
|
998
|
100
|
|
|
|
1747
|
if ($discrete == $order) { |
|
|
50
|
|
|
|
|
|
2043
|
11
|
|
|
|
|
24
|
for (my $val = 1; $val < @tcontr; $val++) { |
2044
|
70
|
100
|
100
|
|
|
155
|
next unless $tcontr[$val] && |
2045
|
|
|
|
|
|
|
$contributed->[$val] > $tcontr[$val]; |
2046
|
|
|
|
|
|
|
|
2047
|
|
|
|
|
|
|
# At this point we know we have an "effective" naked tuple. |
2048
|
|
|
|
|
|
|
|
2049
|
4
|
|
100
|
|
|
16
|
$constraint ||= ['T', 'naked', $order]; |
2050
|
4
|
100
|
|
|
|
9
|
@tuple_member or map {$tuple_member[$_] = 1} @$tuple; |
|
4
|
|
|
|
|
9
|
|
2051
|
4
|
|
|
|
|
7
|
my @ccl; |
2052
|
4
|
|
|
|
|
11
|
for (my $inx = 0; $inx < @$open; $inx++) { |
2053
|
|
|
|
|
|
|
next if $tuple_member[$inx] || |
2054
|
20
|
100
|
100
|
|
|
52
|
$open->[$inx]{possible}{$val}; |
2055
|
10
|
|
|
|
|
14
|
$open->[$inx]{possible}{$val} = 1; |
2056
|
10
|
|
|
|
|
11
|
--$contributed->[$val]; |
2057
|
10
|
|
|
|
|
25
|
push @ccl, $open->[$inx]{index}; |
2058
|
|
|
|
|
|
|
} |
2059
|
4
|
50
|
|
|
|
37
|
push @$constraint, [\@ccl, $val] if @ccl; |
2060
|
|
|
|
|
|
|
} |
2061
|
|
|
|
|
|
|
|
2062
|
|
|
|
|
|
|
# If the number of discrete values is greater than the current |
2063
|
|
|
|
|
|
|
# order, we may have a hidden tuple. The test for an "effective" |
2064
|
|
|
|
|
|
|
# hidden tuple involves massaging @tcontr against @$contributed in |
2065
|
|
|
|
|
|
|
# some way to find a tuple of values within the tuple of cells |
2066
|
|
|
|
|
|
|
# which do not occur outside it. |
2067
|
|
|
|
|
|
|
|
2068
|
|
|
|
|
|
|
} elsif ($discrete > $order) { |
2069
|
987
|
|
|
|
|
1070
|
my $within = 0; # Number of values occuring only |
2070
|
|
|
|
|
|
|
# within tuple. |
2071
|
987
|
|
|
|
|
1562
|
for (my $val = 1; $val < @tcontr; $val++) { |
2072
|
13798
|
100
|
100
|
|
|
28806
|
$within++ if $tcontr[$val] && |
2073
|
|
|
|
|
|
|
$contributed->[$val] == $tcontr[$val]; |
2074
|
|
|
|
|
|
|
} |
2075
|
987
|
100
|
|
|
|
1995
|
next unless $within >= $order; |
2076
|
4
|
|
|
|
|
18
|
$constraint = ['T', 'hidden', $order]; |
2077
|
4
|
|
|
|
|
8
|
map {$tuple_member[$_] = 1} @$tuple; |
|
8
|
|
|
|
|
13
|
|
2078
|
4
|
|
|
|
|
15
|
for (my $val = 1; $val < @tcontr; $val++) { |
2079
|
51
|
100
|
100
|
|
|
124
|
next unless $tcontr[$val] && |
2080
|
|
|
|
|
|
|
$contributed->[$val] > $tcontr[$val]; |
2081
|
11
|
|
|
|
|
18
|
my @ccl; |
2082
|
11
|
|
|
|
|
30
|
for (my $inx = 0; $inx < @$open; $inx++) { |
2083
|
|
|
|
|
|
|
next unless $tuple_member[$inx] |
2084
|
84
|
100
|
100
|
|
|
187
|
&& !$open->[$inx]{possible}{$val} |
2085
|
|
|
|
|
|
|
; |
2086
|
12
|
|
|
|
|
19
|
$open->[$inx]{possible}{$val} = 1; |
2087
|
12
|
|
|
|
|
19
|
--$contributed->[$val]; |
2088
|
12
|
|
|
|
|
42
|
--$tcontr[$val]; |
2089
|
12
|
|
|
|
|
34
|
push @ccl, $open->[$inx]{index}; |
2090
|
|
|
|
|
|
|
} |
2091
|
|
|
|
|
|
|
|
2092
|
11
|
50
|
|
|
|
55
|
push @$constraint, [\@ccl, $val] if @ccl; |
2093
|
|
|
|
|
|
|
} |
2094
|
|
|
|
|
|
|
} |
2095
|
|
|
|
|
|
|
|
2096
|
15
|
100
|
|
|
|
34
|
next unless $constraint; |
2097
|
|
|
|
|
|
|
$self->{debug} and |
2098
|
6
|
50
|
|
|
|
20
|
print '# ', $self->_format_constraint ($constraint); |
2099
|
6
|
|
|
|
|
288
|
return [$constraint]; |
2100
|
|
|
|
|
|
|
} # Next tuple |
2101
|
|
|
|
|
|
|
} # Next set containing vacant cells |
2102
|
|
|
|
|
|
|
} # Next order |
2103
|
|
|
|
|
|
|
|
2104
|
0
|
|
|
|
|
0
|
return []; |
2105
|
|
|
|
|
|
|
} |
2106
|
|
|
|
|
|
|
|
2107
|
|
|
|
|
|
|
# ? constraint - initiate backtracking. |
2108
|
|
|
|
|
|
|
|
2109
|
|
|
|
|
|
|
sub _constraint_backtrack { |
2110
|
0
|
|
|
0
|
|
0
|
my ( $self ) = @_; |
2111
|
|
|
|
|
|
|
## --$iterations >= 0 or return $self->_unload ('', SUDOKU_TOO_HARD) |
2112
|
|
|
|
|
|
|
## if defined $iterations; |
2113
|
0
|
|
|
|
|
0
|
my @try; |
2114
|
0
|
|
|
|
|
0
|
my $syms = @{$self->{symbol_list}}; |
|
0
|
|
|
|
|
0
|
|
2115
|
0
|
|
|
|
|
0
|
foreach my $cell (@{$self->{cell}}) { |
|
0
|
|
|
|
|
0
|
|
2116
|
0
|
0
|
|
|
|
0
|
next if $cell->{content}; |
2117
|
0
|
0
|
|
|
|
0
|
next unless @{$cell->{membership}}; |
|
0
|
|
|
|
|
0
|
|
2118
|
0
|
|
|
|
|
0
|
my $possible = 0; |
2119
|
0
|
|
|
|
|
0
|
for (my $val = 1; $val < $syms; $val++) { |
2120
|
0
|
0
|
|
|
|
0
|
$possible++ unless $cell->{possible}{$val}; |
2121
|
|
|
|
|
|
|
} |
2122
|
0
|
0
|
|
|
|
0
|
$possible or return ['backtrack']; |
2123
|
0
|
|
|
|
|
0
|
push @try, [$cell, $possible]; |
2124
|
|
|
|
|
|
|
} |
2125
|
0
|
|
|
|
|
0
|
@try = map {$_->[0]} sort { |
2126
|
0
|
0
|
|
|
|
0
|
$a->[1] <=> $b->[1] || $a->[0]{index} <=> $b->[0]{index}} @try; |
|
0
|
|
|
|
|
0
|
|
2127
|
0
|
|
|
|
|
0
|
my $cell = $try[0]; |
2128
|
0
|
|
|
|
|
0
|
for (my $val = 1; $val < $syms; $val++) { |
2129
|
0
|
0
|
|
|
|
0
|
next if $cell->{possible}{$val}; |
2130
|
0
|
0
|
|
|
|
0
|
$self->_try ($cell, $val) and confess <
|
2131
|
|
|
|
|
|
|
Programming error - Value $val illegal in cell $cell->{index} for ? constraint, but |
2132
|
|
|
|
|
|
|
\$self->{possible}{$val} = $self->{possible}{$val} |
2133
|
|
|
|
|
|
|
eod |
2134
|
0
|
|
|
|
|
0
|
my $constraint = ['?' => [$cell->{index}, $val]]; |
2135
|
|
|
|
|
|
|
$self->{debug} |
2136
|
0
|
0
|
|
|
|
0
|
and print '# ', $self->_format_constraint ($constraint); |
2137
|
0
|
|
|
|
|
0
|
return [$constraint]; |
2138
|
|
|
|
|
|
|
} |
2139
|
0
|
|
|
|
|
0
|
return []; |
2140
|
|
|
|
|
|
|
} |
2141
|
|
|
|
|
|
|
|
2142
|
|
|
|
|
|
|
# $status_value = $su->_constraint_remove (); |
2143
|
|
|
|
|
|
|
|
2144
|
|
|
|
|
|
|
# This method removes the topmost constraints from the backtrack |
2145
|
|
|
|
|
|
|
# stack. It continues until the next item is a backtrack item or |
2146
|
|
|
|
|
|
|
# the stack is empty. It returns true (SUDOKU_NO_SOLUTION, |
2147
|
|
|
|
|
|
|
# actually) if the stack is emptied, or false (SUDOKU_SUCCESS, |
2148
|
|
|
|
|
|
|
# actually) if it stops because it found a backtrack item. |
2149
|
|
|
|
|
|
|
|
2150
|
|
|
|
|
|
|
# The following arguments may be passed, for use in preparing |
2151
|
|
|
|
|
|
|
# a generated problem: |
2152
|
|
|
|
|
|
|
# - minimum number of cells to leave occupied (no lower limit |
2153
|
|
|
|
|
|
|
# if this is undefined); |
2154
|
|
|
|
|
|
|
# - maximum number of cells to leave occupied (no upper limit |
2155
|
|
|
|
|
|
|
# if this is undefined); |
2156
|
|
|
|
|
|
|
# - a reference to a hash of constraints that it is legal to |
2157
|
|
|
|
|
|
|
# remove. The hash value is the number of times it is |
2158
|
|
|
|
|
|
|
# legal to remove that constraint, or undef if it can |
2159
|
|
|
|
|
|
|
# be removed any number of times. |
2160
|
|
|
|
|
|
|
|
2161
|
|
|
|
|
|
|
sub _constraint_remove { |
2162
|
1
|
|
|
1
|
|
4
|
my ( $self, $min, $max, $removal_ok ) = @_; |
2163
|
1
|
50
|
|
|
|
5
|
$min and $min = @{$self->{cell}} - $min; |
|
0
|
|
|
|
|
0
|
|
2164
|
1
|
50
|
|
|
|
3
|
$max and $max = @{$self->{cell}} - $max; |
|
0
|
|
|
|
|
0
|
|
2165
|
1
|
50
|
|
|
|
4
|
$self->{no_more_solutions} and return SUDOKU_NO_SOLUTION; |
2166
|
1
|
50
|
|
|
|
4
|
my $stack = $self->{backtrack_stack} or return SUDOKU_NO_SOLUTION; |
2167
|
1
|
|
50
|
|
|
4
|
my $used = $self->{constraints_used} ||= {}; |
2168
|
1
|
|
|
|
|
3
|
my $inx = @$stack; |
2169
|
1
|
|
|
|
|
2
|
my $syms = @{$self->{symbol_list}}; |
|
1
|
|
|
|
|
3
|
|
2170
|
1
|
50
|
33
|
|
|
4
|
($self->{debug} && $inx) and print <
|
2171
|
|
|
|
|
|
|
# Debug - Backtracking |
2172
|
|
|
|
|
|
|
eod |
2173
|
1
|
|
|
|
|
2
|
my $old = $inx; |
2174
|
1
|
|
|
|
|
4
|
while (--$inx >= 0) { |
2175
|
45
|
50
|
33
|
|
|
76
|
($min && $self->{cells_unassigned} >= $min) and do { |
2176
|
0
|
0
|
|
|
|
0
|
$self->{debug} and print <
|
2177
|
|
|
|
|
|
|
Debug - Hit minimum occupied cells - returning. |
2178
|
|
|
|
|
|
|
eod |
2179
|
0
|
|
|
|
|
0
|
return SUDOKU_SUCCESS; |
2180
|
|
|
|
|
|
|
}; |
2181
|
45
|
|
|
|
|
58
|
my $constraint = $stack->[$inx][0]; |
2182
|
45
|
50
|
|
|
|
70
|
if ($removal_ok) { |
2183
|
|
|
|
|
|
|
($max && $self->{cells_unassigned} <= $max && |
2184
|
|
|
|
|
|
|
## !$removal_ok->{$constraint} and next; |
2185
|
0
|
0
|
0
|
|
|
0
|
!exists $removal_ok->{$constraint}) and next; |
|
|
|
0
|
|
|
|
|
2186
|
|
|
|
|
|
|
|
2187
|
0
|
0
|
0
|
|
|
0
|
if (!exists $removal_ok->{$constraint}) { |
|
|
0
|
|
|
|
|
|
2188
|
0
|
0
|
|
|
|
0
|
$self->{debug} and print <
|
2189
|
|
|
|
|
|
|
Debug - Encountered constraint $constraint - returning. |
2190
|
|
|
|
|
|
|
eod |
2191
|
0
|
|
|
|
|
0
|
return SUDOKU_SUCCESS; |
2192
|
|
|
|
|
|
|
} elsif (defined $removal_ok->{$constraint} && |
2193
|
|
|
|
|
|
|
--$removal_ok->{$constraint}) { |
2194
|
0
|
0
|
|
|
|
0
|
$self->{debug} and print <
|
2195
|
|
|
|
|
|
|
Debug - Reached usage limit on $constraint - returning. |
2196
|
|
|
|
|
|
|
eod |
2197
|
0
|
|
|
|
|
0
|
return SUDOKU_SUCCESS; |
2198
|
|
|
|
|
|
|
} |
2199
|
|
|
|
|
|
|
} else { |
2200
|
45
|
0
|
33
|
|
|
72
|
($max && $self->{cells_unassigned} <= $max && |
|
|
|
33
|
|
|
|
|
2201
|
|
|
|
|
|
|
$constraint eq '?') |
2202
|
|
|
|
|
|
|
and next; |
2203
|
|
|
|
|
|
|
} |
2204
|
45
|
|
|
|
|
61
|
--$used->{$constraint}; |
2205
|
45
|
50
|
66
|
|
|
74
|
if ($constraint eq 'F' || $constraint eq 'N') { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
2206
|
45
|
|
|
|
|
55
|
foreach my $ref (reverse @{$stack->[$inx]}) { |
|
45
|
|
|
|
|
64
|
|
2207
|
90
|
100
|
|
|
|
161
|
$self->_try ($ref->[0], 0) if ref $ref; |
2208
|
|
|
|
|
|
|
} |
2209
|
|
|
|
|
|
|
} elsif ($constraint eq 'B' || $constraint eq 'T') { |
2210
|
0
|
|
|
|
|
0
|
foreach my $ref (reverse @{$stack->[$inx]}) { |
|
0
|
|
|
|
|
0
|
|
2211
|
0
|
0
|
|
|
|
0
|
next unless ref $ref; |
2212
|
0
|
|
|
|
|
0
|
my $val = $ref->[1]; |
2213
|
0
|
|
|
|
|
0
|
foreach my $inx (@{$ref->[0]}) { |
|
0
|
|
|
|
|
0
|
|
2214
|
0
|
|
|
|
|
0
|
$self->{cell}[$inx]{possible}{$val} = 0; |
2215
|
|
|
|
|
|
|
} |
2216
|
|
|
|
|
|
|
} |
2217
|
|
|
|
|
|
|
} elsif ($constraint eq '?') { |
2218
|
0
|
|
|
|
|
0
|
my $start = $stack->[$inx][1][1] + 1; |
2219
|
0
|
|
|
|
|
0
|
my $cell = $self->{cell}[$stack->[$inx][1][0]]; |
2220
|
0
|
|
|
|
|
0
|
$self->_try ($cell, 0); |
2221
|
0
|
0
|
|
|
|
0
|
next if $removal_ok; |
2222
|
0
|
|
|
|
|
0
|
for (my $val = $start; $val < $syms; $val++) { |
2223
|
0
|
0
|
|
|
|
0
|
next if $cell->{possible}{$val}; |
2224
|
0
|
0
|
|
|
|
0
|
$self->_try ($cell, $val) and confess <
|
2225
|
|
|
|
|
|
|
Programming error - Try of $val in cell $cell->{index} failed, but |
2226
|
|
|
|
|
|
|
\$cell->{possible}[$inx] = $cell->{possible}[$inx] |
2227
|
|
|
|
|
|
|
eod |
2228
|
0
|
|
|
|
|
0
|
$used->{$constraint}++; |
2229
|
0
|
|
|
|
|
0
|
$stack->[$inx][1][0] = $cell->{index}; |
2230
|
0
|
|
|
|
|
0
|
$stack->[$inx][1][1] = $val; |
2231
|
0
|
0
|
|
|
|
0
|
$self->{debug} and do { |
2232
|
0
|
|
|
|
|
0
|
my $x = $self->_format_constraint ($stack->[$inx]); |
2233
|
0
|
|
|
|
|
0
|
chomp $x; |
2234
|
0
|
|
|
|
|
0
|
print <
|
2235
|
0
|
|
|
|
|
0
|
# Debug - Backtrack complete. @{[$old - @$stack]} constraints removed. |
2236
|
0
|
|
|
|
|
0
|
# Resuming puzzle at stack depth @{[$inx + 1]} with |
2237
|
|
|
|
|
|
|
# $self->{cells_unassigned} unassigned cells, guessing |
2238
|
|
|
|
|
|
|
# $x |
2239
|
|
|
|
|
|
|
eod |
2240
|
|
|
|
|
|
|
}; |
2241
|
0
|
|
|
|
|
0
|
return SUDOKU_SUCCESS; |
2242
|
|
|
|
|
|
|
} |
2243
|
0
|
|
|
|
|
0
|
} else {confess <
|
2244
|
|
|
|
|
|
|
Programming Error - No code provided to remove constraint '$constraint' from stack. |
2245
|
|
|
|
|
|
|
eod |
2246
|
|
|
|
|
|
|
} |
2247
|
45
|
|
|
|
|
87
|
pop @$stack; |
2248
|
|
|
|
|
|
|
} |
2249
|
1
|
50
|
|
|
|
5
|
$self->{debug} and print <
|
2250
|
0
|
|
|
|
|
0
|
# Debug - Backtrack complete. @{[$old - @$stack]} constraints removed. |
2251
|
|
|
|
|
|
|
# No more solutions to the puzzle exist. |
2252
|
|
|
|
|
|
|
eod |
2253
|
1
|
|
|
|
|
2
|
$self->{no_more_solutions} = 1; |
2254
|
1
|
|
|
|
|
6
|
return SUDOKU_NO_SOLUTION; |
2255
|
|
|
|
|
|
|
} |
2256
|
|
|
|
|
|
|
|
2257
|
|
|
|
|
|
|
# $self->_deprecation_notice( $name ); |
2258
|
|
|
|
|
|
|
# |
2259
|
|
|
|
|
|
|
# This method centralizes deprecation. Deprecation is driven of |
2260
|
|
|
|
|
|
|
# the %deprecate hash. Level values are: |
2261
|
|
|
|
|
|
|
# false - no warning |
2262
|
|
|
|
|
|
|
# 1 - warn on first use |
2263
|
|
|
|
|
|
|
# 2 - warn on each use |
2264
|
|
|
|
|
|
|
# 3 - die on each use. |
2265
|
|
|
|
|
|
|
|
2266
|
|
|
|
|
|
|
{ |
2267
|
|
|
|
|
|
|
|
2268
|
|
|
|
|
|
|
my %deprecate = ( |
2269
|
|
|
|
|
|
|
brick_third_argument => { |
2270
|
|
|
|
|
|
|
message => 'Specifying 3 values for set( brick => ... ) is no longer allowed', |
2271
|
|
|
|
|
|
|
level => 3, |
2272
|
|
|
|
|
|
|
}, |
2273
|
|
|
|
|
|
|
); |
2274
|
|
|
|
|
|
|
|
2275
|
|
|
|
|
|
|
sub _deprecation_notice { |
2276
|
0
|
|
|
0
|
|
0
|
my ( undef, $name ) = @_; # Invocant unused |
2277
|
0
|
0
|
|
|
|
0
|
my $info = $deprecate{$name} |
2278
|
|
|
|
|
|
|
or return; |
2279
|
|
|
|
|
|
|
$info->{level} |
2280
|
0
|
0
|
|
|
|
0
|
or return; |
2281
|
|
|
|
|
|
|
$info->{level} >= 3 |
2282
|
0
|
0
|
|
|
|
0
|
and croak $info->{message}; |
2283
|
|
|
|
|
|
|
warnings::enabled( 'deprecated' ) |
2284
|
0
|
0
|
|
|
|
0
|
and carp $info->{message}; |
2285
|
|
|
|
|
|
|
$info->{level} == 1 |
2286
|
0
|
0
|
|
|
|
0
|
and $info->{level} = 0; |
2287
|
0
|
|
|
|
|
0
|
return; |
2288
|
|
|
|
|
|
|
} |
2289
|
|
|
|
|
|
|
|
2290
|
|
|
|
|
|
|
} |
2291
|
|
|
|
|
|
|
|
2292
|
|
|
|
|
|
|
# _format_constraint formats the given constraint for output. |
2293
|
|
|
|
|
|
|
|
2294
|
|
|
|
|
|
|
sub _format_constraint { |
2295
|
1
|
|
|
1
|
|
5
|
my ($self, @args) = @_; |
2296
|
1
|
|
|
|
|
2
|
my @steps; |
2297
|
1
|
|
|
|
|
3
|
foreach (@args) { |
2298
|
52
|
|
|
|
|
58
|
my @stuff; |
2299
|
52
|
|
|
|
|
70
|
foreach (@$_) { |
2300
|
104
|
50
|
|
|
|
145
|
last unless $_; |
2301
|
|
|
|
|
|
|
push @stuff, ref $_ ? |
2302
|
|
|
|
|
|
|
'[' . join (' ', |
2303
|
0
|
|
|
|
|
0
|
ref $_->[0] ? '[' . join (', ', @{$_->[0]}) . ']' : $_->[0], |
2304
|
|
|
|
|
|
|
ref $_->[1] ? '[' . join (', ', |
2305
|
0
|
|
|
|
|
0
|
map {$self->{symbol_list}[$_]} @{$_->[1]}) . ']' : |
|
0
|
|
|
|
|
0
|
|
2306
|
104
|
50
|
|
|
|
237
|
$self->{symbol_list}[$_->[1]], |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
2307
|
|
|
|
|
|
|
) . ']' : |
2308
|
|
|
|
|
|
|
$_; |
2309
|
|
|
|
|
|
|
} |
2310
|
52
|
|
|
|
|
126
|
push @steps, join (' ', @stuff) . "\n"; |
2311
|
|
|
|
|
|
|
} |
2312
|
1
|
|
|
|
|
10
|
return join '', @steps; |
2313
|
|
|
|
|
|
|
} |
2314
|
|
|
|
|
|
|
|
2315
|
|
|
|
|
|
|
# _looks_like_number is cribbed heavily from |
2316
|
|
|
|
|
|
|
# Scalar::Util::looks_like_number by Graham Barr. This version |
2317
|
|
|
|
|
|
|
# only accepts integers, but it is really here because |
2318
|
|
|
|
|
|
|
# ActivePerl's Scalar::Util is too ancient to export |
2319
|
|
|
|
|
|
|
# looks_like_number. |
2320
|
|
|
|
|
|
|
|
2321
|
|
|
|
|
|
|
sub _looks_like_number { |
2322
|
44
|
|
|
44
|
|
83
|
( local $_ ) = @_; |
2323
|
44
|
50
|
33
|
|
|
160
|
return 0 if !defined ($_) || ref ($_); |
2324
|
44
|
50
|
|
|
|
343
|
return 1 if m/^[+-]?\d+$/; |
2325
|
0
|
|
|
|
|
0
|
return 0; |
2326
|
|
|
|
|
|
|
} |
2327
|
|
|
|
|
|
|
|
2328
|
|
|
|
|
|
|
# _set_* subroutines are found right after the set() method. |
2329
|
|
|
|
|
|
|
|
2330
|
|
|
|
|
|
|
# $su->_try ($cell, $value) |
2331
|
|
|
|
|
|
|
|
2332
|
|
|
|
|
|
|
# This method inserts the given value in the given cell, |
2333
|
|
|
|
|
|
|
# replacing the previous value if any, and doing all the |
2334
|
|
|
|
|
|
|
# bookkeeping. If the given value is legal (meaning, if |
2335
|
|
|
|
|
|
|
# it is zero or if it is unique in all sets the cell |
2336
|
|
|
|
|
|
|
# belongs to), it returns 0. If not, it returns 1, but |
2337
|
|
|
|
|
|
|
# does not undo the trial. |
2338
|
|
|
|
|
|
|
|
2339
|
|
|
|
|
|
|
sub _try { |
2340
|
2815
|
|
|
2815
|
|
4067
|
my ( $self, $cell, $new ) = @_; |
2341
|
2815
|
100
|
|
|
|
4550
|
$cell = $self->{cell}[$cell] unless ref $cell; |
2342
|
2815
|
50
|
|
|
|
4328
|
defined $new |
2343
|
|
|
|
|
|
|
or _fatal ( |
2344
|
|
|
|
|
|
|
"_try called for cell $cell->{index} with new value undefined"); |
2345
|
2815
|
50
|
|
|
|
4239
|
defined (my $old = $cell->{content}) or _fatal ( |
2346
|
|
|
|
|
|
|
"_try called with old cell $cell->{index} value undefined"); |
2347
|
2815
|
|
|
|
|
3241
|
my $rslt = eval { |
2348
|
2815
|
100
|
|
|
|
4534
|
return 0 if $old == $new; |
2349
|
1644
|
100
|
|
|
|
2449
|
if ($new) { |
2350
|
1599
|
|
|
|
|
1788
|
foreach my $set (@{$cell->{membership}}) { |
|
1599
|
|
|
|
|
2529
|
|
2351
|
4833
|
50
|
|
|
|
9123
|
return 1 if $self->{set}{$set}{content}[$new]; |
2352
|
|
|
|
|
|
|
} |
2353
|
|
|
|
|
|
|
} |
2354
|
1644
|
|
|
|
|
2377
|
$cell->{content} = $new; |
2355
|
1644
|
100
|
|
|
|
2291
|
$old and $self->{cells_unassigned}++; |
2356
|
1644
|
100
|
|
|
|
2580
|
$new and --$self->{cells_unassigned}; |
2357
|
1644
|
|
|
|
|
1765
|
foreach my $name (@{$cell->{membership}}) { |
|
1644
|
|
|
|
|
2334
|
|
2358
|
4968
|
|
|
|
|
6327
|
my $set = $self->{set}{$name}; |
2359
|
4968
|
|
|
|
|
5679
|
--$set->{content}[$old]; |
2360
|
4968
|
100
|
|
|
|
6791
|
$old and do { |
2361
|
135
|
|
|
|
|
149
|
$set->{free}++; |
2362
|
135
|
|
|
|
|
143
|
foreach (@{$set->{membership}}) { |
|
135
|
|
|
|
|
173
|
|
2363
|
1215
|
|
|
|
|
1567
|
--$self->{cell}[$_]{possible}{$old}; |
2364
|
|
|
|
|
|
|
} |
2365
|
|
|
|
|
|
|
}; |
2366
|
4968
|
|
|
|
|
6663
|
$set->{content}[$new]++; |
2367
|
4968
|
100
|
|
|
|
6936
|
$new and do { |
2368
|
4833
|
|
|
|
|
5371
|
--$set->{free}; |
2369
|
4833
|
|
|
|
|
5255
|
foreach (@{$set->{membership}}) { |
|
4833
|
|
|
|
|
6740
|
|
2370
|
50421
|
|
|
|
|
69566
|
$self->{cell}[$_]{possible}{$new}++; |
2371
|
|
|
|
|
|
|
} |
2372
|
|
|
|
|
|
|
}; |
2373
|
|
|
|
|
|
|
} |
2374
|
1644
|
|
|
|
|
2218
|
return 0; |
2375
|
|
|
|
|
|
|
}; |
2376
|
2815
|
50
|
|
|
|
4094
|
$@ and _fatal ("Eval failed in _try", $@); |
2377
|
2815
|
|
|
|
|
4552
|
return $rslt; |
2378
|
|
|
|
|
|
|
} |
2379
|
|
|
|
|
|
|
|
2380
|
|
|
|
|
|
|
# $string = $self->_unload (prefix, status_value) |
2381
|
|
|
|
|
|
|
|
2382
|
|
|
|
|
|
|
# This method unloads the current cell contents into a string. |
2383
|
|
|
|
|
|
|
# The prefix is prefixed to the string, and defaults to ''. |
2384
|
|
|
|
|
|
|
# If status_value is specified, it is set. If status_value is |
2385
|
|
|
|
|
|
|
# specified and it is a failure status, undef is returned, and |
2386
|
|
|
|
|
|
|
# the current cell contents are ignored. |
2387
|
|
|
|
|
|
|
|
2388
|
|
|
|
|
|
|
sub _unload { |
2389
|
23
|
|
|
23
|
|
58
|
my ($self, $prefix, @args) = @_; |
2390
|
23
|
100
|
|
|
|
64
|
defined $prefix or $prefix = ''; |
2391
|
23
|
100
|
|
|
|
52
|
@args and do { |
2392
|
19
|
|
|
|
|
90
|
$self->set (status_value => $args[0]); |
2393
|
19
|
100
|
|
|
|
51
|
$args[0] and return; |
2394
|
|
|
|
|
|
|
}; |
2395
|
22
|
|
|
|
|
39
|
my $rslt = ''; |
2396
|
22
|
|
|
|
|
39
|
my $col = $self->{columns}; |
2397
|
22
|
|
33
|
|
|
46
|
my $row = $self->{rows} ||= floor (@{$self->{cell}} / $col); |
|
0
|
|
|
|
|
0
|
|
2398
|
22
|
|
|
|
|
70
|
my $fmt = "%$self->{biggest_symbol}s"; |
2399
|
22
|
|
|
|
|
30
|
foreach (@{$self->{cell}}) { |
|
22
|
|
|
|
|
54
|
|
2400
|
1894
|
100
|
|
|
|
2614
|
$col == $self->{columns} and $rslt .= $prefix; |
2401
|
|
|
|
|
|
|
# was $self->{ignore_unused} |
2402
|
|
|
|
|
|
|
$rslt .= ($self->{cells_unused} && !@{$_->{membership}}) ? |
2403
|
|
|
|
|
|
|
sprintf ($fmt, ' ') : |
2404
|
1894
|
50
|
33
|
|
|
4503
|
sprintf ($fmt, $self->{symbol_list}[$_->{content} || 0]); |
|
|
|
100
|
|
|
|
|
2405
|
1894
|
100
|
|
|
|
2457
|
if (--$col > 0) { |
2406
|
|
|
|
|
|
|
$rslt .= $self->{output_delimiter} |
2407
|
1674
|
|
|
|
|
2207
|
} else { |
2408
|
|
|
|
|
|
|
# was $self->{ignore_unused} |
2409
|
220
|
50
|
|
|
|
344
|
$self->{cells_unused} and $rslt =~ s/\s+$//m; |
2410
|
220
|
|
|
|
|
262
|
$rslt .= "\n"; |
2411
|
220
|
|
|
|
|
264
|
$col = $self->{columns}; |
2412
|
220
|
100
|
|
|
|
355
|
if (--$row <= 0) { |
2413
|
29
|
|
|
|
|
38
|
$rslt .= "\n"; |
2414
|
29
|
|
|
|
|
52
|
$row = $self->{rows}; |
2415
|
|
|
|
|
|
|
} |
2416
|
|
|
|
|
|
|
} |
2417
|
|
|
|
|
|
|
} |
2418
|
22
|
|
|
|
|
86
|
0 while chomp $rslt; |
2419
|
22
|
|
|
|
|
30
|
$rslt .= "\n"; |
2420
|
22
|
|
|
|
|
257
|
return $rslt; |
2421
|
|
|
|
|
|
|
} |
2422
|
|
|
|
|
|
|
|
2423
|
|
|
|
|
|
|
1; |
2424
|
|
|
|
|
|
|
|
2425
|
|
|
|
|
|
|
__END__ |