ruby-minisat 1.14.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +24 -0
- data/LICENSE +21 -0
- data/README.rdoc +56 -0
- data/Rakefile +48 -0
- data/VERSION +1 -0
- data/examples/compat18.rb +65 -0
- data/examples/example.rb +26 -0
- data/examples/example2.rb +60 -0
- data/examples/kakuro.rb +178 -0
- data/examples/kakuro.sample +13 -0
- data/examples/lonely7.rb +302 -0
- data/examples/nonogram.rb +254 -0
- data/examples/nonogram.sample +26 -0
- data/examples/numberlink.rb +489 -0
- data/examples/numberlink.sample +11 -0
- data/examples/shikaku.rb +190 -0
- data/examples/shikaku.sample +11 -0
- data/examples/slitherlink.rb +279 -0
- data/examples/slitherlink.sample +11 -0
- data/examples/sudoku.rb +216 -0
- data/examples/sudoku.sample +11 -0
- data/ext/minisat/extconf.rb +9 -0
- data/ext/minisat/minisat-wrap.cpp +88 -0
- data/ext/minisat/minisat.c +497 -0
- data/ext/minisat/minisat.h +53 -0
- data/minisat/MiniSat_v1.14.2006-Aug-29.src.zip +0 -0
- data/minisat/MiniSat_v1.14/Global.h +274 -0
- data/minisat/MiniSat_v1.14/Heap.h +100 -0
- data/minisat/MiniSat_v1.14/LICENSE +20 -0
- data/minisat/MiniSat_v1.14/Main.C +244 -0
- data/minisat/MiniSat_v1.14/Makefile +88 -0
- data/minisat/MiniSat_v1.14/README +30 -0
- data/minisat/MiniSat_v1.14/Solver.C +781 -0
- data/minisat/MiniSat_v1.14/Solver.h +206 -0
- data/minisat/MiniSat_v1.14/Solver.o +0 -0
- data/minisat/MiniSat_v1.14/SolverTypes.h +130 -0
- data/minisat/MiniSat_v1.14/Sort.h +131 -0
- data/minisat/MiniSat_v1.14/TODO +73 -0
- data/minisat/MiniSat_v1.14/VarOrder.h +96 -0
- data/test/test_minisat.rb +143 -0
- metadata +114 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
# quoted from wikipedia (http://en.wikipedia.org/wiki/Nonogram)
|
2
|
+
1 1
|
3
|
+
1 1 3 3
|
4
|
+
3 2 1 3 2 3 5 1 2 3 2 2
|
5
|
+
1 2 2 1 1 2 1 6 9 3 2 1 3 2 1 2 2
|
6
|
+
2 2 3 3 1 1 2 3 4 1 2 2 7 2 4 2 1 2 1 1
|
7
|
+
3 . . . . . . . . . . . . . . . . . . . .
|
8
|
+
5 . . . . . . . . . . . . . . . . . . . .
|
9
|
+
3 1 . . . . . . . . . . . . . . . . . . . .
|
10
|
+
2 1 . . . . . . . . . . . . . . . . . . . .
|
11
|
+
3 3 4 . . . . . . . . . . . . . . . . . . . .
|
12
|
+
2 2 7 . . . . . . . . . . . . . . . . . . . .
|
13
|
+
6 1 1 . . . . . . . . . . . . . . . . . . . .
|
14
|
+
4 2 2 . . . . . . . . . . . . . . . . . . . .
|
15
|
+
1 1 . . . . . . . . . . . . . . . . . . . .
|
16
|
+
3 1 . . . . . . . . . . . . . . . . . . . .
|
17
|
+
6 . . . . . . . . . . . . . . . . . . . .
|
18
|
+
2 7 . . . . . . . . . . . . . . . . . . . .
|
19
|
+
6 3 1 . . . . . . . . . . . . . . . . . . . .
|
20
|
+
1 2 2 1 1 . . . . . . . . . . . . . . . . . . . .
|
21
|
+
4 1 1 3 . . . . . . . . . . . . . . . . . . . .
|
22
|
+
4 2 2 . . . . . . . . . . . . . . . . . . . .
|
23
|
+
3 3 1 . . . . . . . . . . . . . . . . . . . .
|
24
|
+
3 3 . . . . . . . . . . . . . . . . . . . .
|
25
|
+
3 . . . . . . . . . . . . . . . . . . . .
|
26
|
+
2 1 . . . . . . . . . . . . . . . . . . . .
|
@@ -0,0 +1,489 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# ruby-minisat example -- numberlink.rb
|
4
|
+
# ref: http://en.wikipedia.org/wiki/Number_Link
|
5
|
+
|
6
|
+
##
|
7
|
+
## SAT configuration:
|
8
|
+
## - Variables:
|
9
|
+
## - to each number cell:
|
10
|
+
## - 4 variables for directions
|
11
|
+
## - to each blank cell:
|
12
|
+
## - 7 variables for patterns
|
13
|
+
## - n variables for numbers
|
14
|
+
## - the line of the cell links this numbers
|
15
|
+
## - Clauses:
|
16
|
+
## - exact one directions in each number cell
|
17
|
+
## - exact one pattern in each blank cell
|
18
|
+
## - zero linked numbers in each blank cell if the cell is blank
|
19
|
+
## - exact one linked numbers if each blank cell if the cell has a line
|
20
|
+
## - no blank pattern (if filled solution is required)
|
21
|
+
## - neighbor blank cells are connected or disconnected
|
22
|
+
## - line links continuously the two same numbers
|
23
|
+
## - connectivity optimization (below)
|
24
|
+
## - neighbor blank cells links the same number if they are connected
|
25
|
+
## - patterns are false which makes line out of field
|
26
|
+
## - blank cell in the direction of number cell connects the number cell
|
27
|
+
## - blank cells not in the direction of number cell does not connects the
|
28
|
+
## number cell
|
29
|
+
## - corner optimization (below)
|
30
|
+
##
|
31
|
+
## patterns:
|
32
|
+
## - 0 : vertical line
|
33
|
+
## - 1 : orthogonal line (up and left)
|
34
|
+
## - 2 : orthogonal line (up and right)
|
35
|
+
## - 3 : orthogonal line (down and left)
|
36
|
+
## - 4 : orthogonal line (down and right)
|
37
|
+
## - 5 : horizontal line
|
38
|
+
## - 6 : blank
|
39
|
+
##
|
40
|
+
## | | |
|
41
|
+
## 0 --1 2-- --3 4-- --5--
|
42
|
+
## | | |
|
43
|
+
##
|
44
|
+
##
|
45
|
+
## basic connectivity:
|
46
|
+
## [0, 3, 4]
|
47
|
+
## |
|
48
|
+
## [2, 4, 5]---+---[1, 3, 5]
|
49
|
+
## |
|
50
|
+
## [0, 1, 2]
|
51
|
+
##
|
52
|
+
##
|
53
|
+
## connectivity optimization: prune U-turn situations
|
54
|
+
## For example, left pattern is 2 and right one is 1.
|
55
|
+
## In such situations, the shortcut exists:
|
56
|
+
##
|
57
|
+
## + + +---+
|
58
|
+
## | | =>
|
59
|
+
## 2---1 b b
|
60
|
+
##
|
61
|
+
##
|
62
|
+
## extended horizontal connectivity:
|
63
|
+
## l\r 1 3 5
|
64
|
+
## 2 o o
|
65
|
+
## 4 o o
|
66
|
+
## 5 o o o
|
67
|
+
##
|
68
|
+
## extended veritcal connectivity:
|
69
|
+
## u\d 0 1 2
|
70
|
+
## 0 o o o
|
71
|
+
## 3 o o
|
72
|
+
## 4 o o
|
73
|
+
##
|
74
|
+
##
|
75
|
+
## corner optimization: patterns 1 and 2 exists only `corner of number'
|
76
|
+
## - pattern 1 can be only in the lower right-hand corner of number or 1
|
77
|
+
## - pattern 2 can be only in the lower left-hand corner of number or 2
|
78
|
+
##
|
79
|
+
##
|
80
|
+
## n + + n
|
81
|
+
## | |
|
82
|
+
## +---1 + + 2---+
|
83
|
+
## | |
|
84
|
+
## +---1 + + 2---+
|
85
|
+
## | |
|
86
|
+
## +---1 2---+
|
87
|
+
##
|
88
|
+
## directions:
|
89
|
+
## - 0: up
|
90
|
+
## - 1: down
|
91
|
+
## - 2: left
|
92
|
+
## - 3: right
|
93
|
+
##
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
require "minisat"
|
98
|
+
require File.dirname($0) + "/compat18" if RUBY_VERSION < "1.9.0"
|
99
|
+
|
100
|
+
$filled = true
|
101
|
+
|
102
|
+
|
103
|
+
def error(msg)
|
104
|
+
$stderr.puts msg
|
105
|
+
exit 1
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
def parse_file(file)
|
110
|
+
width = nil
|
111
|
+
field = []
|
112
|
+
File.read(file).split(/\n/).each do |line|
|
113
|
+
case line
|
114
|
+
when /^\s*#.*$/, /^\s*$/
|
115
|
+
else
|
116
|
+
line = line.split.map {|x| x[/^\d+$/] && x.to_i }
|
117
|
+
width ||= line.size
|
118
|
+
unless width == line.size
|
119
|
+
error "illegal width: row #{ field.size + 1 }"
|
120
|
+
end
|
121
|
+
field << line
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
h = {}
|
126
|
+
field.flatten.compact.sort.each_slice(2) do |x, y|
|
127
|
+
error "bad field" if x == 0 || x != y || h[x]
|
128
|
+
h[x] = true
|
129
|
+
end
|
130
|
+
|
131
|
+
field
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
def define_sat(solver, field)
|
136
|
+
w = field.first.size
|
137
|
+
h = field.size
|
138
|
+
|
139
|
+
num = field.flatten.compact.uniq.size
|
140
|
+
|
141
|
+
# define variables:
|
142
|
+
# - 4 variables (directions) to each number cell
|
143
|
+
# - 7 (patterns) + n (numbers) variables to each blank cell
|
144
|
+
vars = field.map do |line|
|
145
|
+
line.map do |c|
|
146
|
+
if c
|
147
|
+
# number cell
|
148
|
+
dirs = (0...4).map { solver.new_var }
|
149
|
+
|
150
|
+
# exact one directions
|
151
|
+
exact_one(solver, dirs)
|
152
|
+
|
153
|
+
dirs
|
154
|
+
else
|
155
|
+
# blank cell
|
156
|
+
pats = (0...7).map { solver.new_var }
|
157
|
+
nums = (0...num).map { solver.new_var }
|
158
|
+
|
159
|
+
# exact one pattern
|
160
|
+
exact_one(solver, pats)
|
161
|
+
|
162
|
+
# zero connected numbers in each blank cell if the cell is blank
|
163
|
+
# exact one connected numbers if each blank cell if the cell has a line
|
164
|
+
([pats.last] + nums).combination(2) {|v1, v2| solver << [-v1, -v2] }
|
165
|
+
|
166
|
+
# no blank pattern (if filled solution is required)
|
167
|
+
solver << -pats.last if $filled
|
168
|
+
|
169
|
+
[pats, nums]
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# define connection rule
|
175
|
+
field.each_with_index do |line, y|
|
176
|
+
line.each_with_index do |num, x|
|
177
|
+
if num
|
178
|
+
number_connectivity(solver, field, vars, x, y, w, h)
|
179
|
+
else
|
180
|
+
line_connectivity(solver, field, vars, x, y, w, h)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# corner optimization
|
186
|
+
l_corner, r_corner = {}, {}
|
187
|
+
field.each_with_index do |line, y|
|
188
|
+
line.each_with_index do |num, x|
|
189
|
+
if num
|
190
|
+
l_corner[[x - 1, y + 1]] = r_corner[[x + 1, y + 1]] = true
|
191
|
+
else
|
192
|
+
if l_corner[[x, y]]
|
193
|
+
l_corner[[x - 1, y + 1]] = true
|
194
|
+
if !field[y - 1][x + 1]
|
195
|
+
solver << [-vars[y][x].first[2], vars[y - 1][x + 1].first[2]]
|
196
|
+
end
|
197
|
+
else
|
198
|
+
solver << -vars[y][x].first[2]
|
199
|
+
end
|
200
|
+
if r_corner[[x, y]]
|
201
|
+
r_corner[[x + 1, y + 1]] = true
|
202
|
+
if !field[y - 1][x - 1]
|
203
|
+
solver << [-vars[y][x].first[1], vars[y - 1][x - 1].first[1]]
|
204
|
+
end
|
205
|
+
else
|
206
|
+
solver << -vars[y][x].first[1]
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
vars
|
213
|
+
end
|
214
|
+
|
215
|
+
|
216
|
+
# basic connectivity
|
217
|
+
U_CON = [0, 3, 4]
|
218
|
+
L_CON, R_CON = [2, 4, 5], [1, 3, 5]
|
219
|
+
D_CON = [0, 1, 2]
|
220
|
+
|
221
|
+
|
222
|
+
DIR = [[0, -1], [0, 1], [-1, 0], [1, 0]]
|
223
|
+
|
224
|
+
|
225
|
+
def line_connectivity(solver, field, vars, x, y, w, h)
|
226
|
+
if x < w - 1 && !field[y][x + 1]
|
227
|
+
l_pats, l_nums = vars[y][x]
|
228
|
+
r_pats, r_nums = vars[y][x + 1]
|
229
|
+
|
230
|
+
# extended horizontal connectivity
|
231
|
+
solver << [-l_pats[2], r_pats[3], r_pats[5]]
|
232
|
+
solver << [-l_pats[4], r_pats[1], r_pats[5]]
|
233
|
+
solver << [-l_pats[5], r_pats[1], r_pats[3], r_pats[5]]
|
234
|
+
solver << [-r_pats[1], l_pats[4], l_pats[5]]
|
235
|
+
solver << [-r_pats[3], l_pats[2], l_pats[5]]
|
236
|
+
solver << [-r_pats[5], l_pats[2], l_pats[4], l_pats[5]]
|
237
|
+
|
238
|
+
# the same number if connected
|
239
|
+
l_nums.zip(r_nums) do |l_num, r_num|
|
240
|
+
L_CON.each do |i|
|
241
|
+
solver << [-l_pats[i], -l_num, r_num] << [-l_pats[i], l_num, -r_num]
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
if y < h - 1 && !field[y + 1][x]
|
247
|
+
u_pats, u_nums = vars[y][x]
|
248
|
+
d_pats, d_nums = vars[y + 1][x]
|
249
|
+
|
250
|
+
# extended vartical connectivity
|
251
|
+
solver << [-u_pats[0], d_pats[0], d_pats[1], d_pats[2]]
|
252
|
+
solver << [-u_pats[3], d_pats[0], d_pats[2]]
|
253
|
+
solver << [-u_pats[4], d_pats[0], d_pats[1] ]
|
254
|
+
solver << [-d_pats[0], u_pats[0], u_pats[3], u_pats[4]]
|
255
|
+
solver << [-d_pats[1], u_pats[0], u_pats[4]]
|
256
|
+
solver << [-d_pats[2], u_pats[0], u_pats[3] ]
|
257
|
+
|
258
|
+
# the same number if connected
|
259
|
+
u_nums.zip(d_nums) do |u_num, d_num|
|
260
|
+
U_CON.each do |i|
|
261
|
+
solver << [-u_pats[i], -u_num, d_num] << [-u_pats[i], u_num, -d_num]
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
# edges of field
|
267
|
+
R_CON.map {|i| solver << -vars[y][x].first[i] } if x == 0
|
268
|
+
L_CON.map {|i| solver << -vars[y][x].first[i] } if x == w - 1
|
269
|
+
D_CON.map {|i| solver << -vars[y][x].first[i] } if y == 0
|
270
|
+
U_CON.map {|i| solver << -vars[y][x].first[i] } if y == h - 1
|
271
|
+
end
|
272
|
+
|
273
|
+
|
274
|
+
def number_connectivity(solver, field, vars, x, y, w, h)
|
275
|
+
rev = [U_CON, D_CON, L_CON, R_CON].zip(DIR).to_a
|
276
|
+
num = field[y][x]
|
277
|
+
|
278
|
+
4.times do |i|
|
279
|
+
dir = vars[y][x][i]
|
280
|
+
con, (xo, yo) = rev[0]
|
281
|
+
x2, y2 = x + xo, y + yo
|
282
|
+
if x2 >= 0 && x2 < w && y2 >= 0 && y2 < h && !field[y2][x2]
|
283
|
+
pats, nums = vars[y2][x2]
|
284
|
+
solver << [-dir, nums[num - 1]]
|
285
|
+
solver << [-dir] + con.map {|i| pats[i] }
|
286
|
+
(pats - con.map {|i| pats[i] }).each {|v| solver << [-dir, -v] }
|
287
|
+
(1..3).each do |j|
|
288
|
+
con, (xo, yo) = rev[j]
|
289
|
+
x2, y2 = x + xo, y + yo
|
290
|
+
if x2 >= 0 && x2 < w && y2 >= 0 && y2 < h && !field[y2][x2]
|
291
|
+
pats, nums = vars[y2][x2]
|
292
|
+
con.each {|i| solver << [-dir, -pats[i]] }
|
293
|
+
solver << [-dir] + (pats - con.map {|i| pats[i] })
|
294
|
+
end
|
295
|
+
end
|
296
|
+
elsif x2 >= 0 && x2 < w && y2 >= 0 && y2 < h && num == field[y2][x2]
|
297
|
+
solver << dir
|
298
|
+
else
|
299
|
+
solver << -dir
|
300
|
+
end
|
301
|
+
rev << rev.shift
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
|
306
|
+
def exact_one(solver, vars)
|
307
|
+
solver << vars
|
308
|
+
vars.combination(2) {|v1, v2| solver << [-v1, -v2] }
|
309
|
+
end
|
310
|
+
|
311
|
+
|
312
|
+
def make_solution(solver, vars, field)
|
313
|
+
field.zip(vars).map do |fline, vline|
|
314
|
+
fline.zip(vline).map do |num, vs|
|
315
|
+
if num
|
316
|
+
(0...4).find {|i| solver[vs[i]] }
|
317
|
+
else
|
318
|
+
(0...7).find {|i| solver[vs.first[i]] }
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
|
325
|
+
def add_constraint(solver, vars)
|
326
|
+
solver << vars.flatten.map {|v| solver[v] ? -v : v }
|
327
|
+
end
|
328
|
+
|
329
|
+
|
330
|
+
def output_field(solution, field)
|
331
|
+
w = field.first.size
|
332
|
+
h = field.size
|
333
|
+
ary = (0 ... h).map { (0 ... w).map { nil } }
|
334
|
+
|
335
|
+
solution.each_with_index do |line, y|
|
336
|
+
line.each_with_index do |c, x|
|
337
|
+
num = field[y][x]
|
338
|
+
ary[y][x] = if num
|
339
|
+
case c
|
340
|
+
when 0 then [" #{ num }"[-4..-1], " "]
|
341
|
+
when 1 then [" #{ num }"[-4..-1], " |"]
|
342
|
+
when 2 then ["----#{ num }"[-4..-1], " "]
|
343
|
+
when 3 then [" #{ num }"[-4..-1], " "]
|
344
|
+
end
|
345
|
+
else
|
346
|
+
case c
|
347
|
+
when 0 then [" +", " |"]
|
348
|
+
when 1 then ["---+", " "]
|
349
|
+
when 2 then [" +", " "]
|
350
|
+
when 3 then ["---+", " |"]
|
351
|
+
when 4 then [" +", " |"]
|
352
|
+
when 5 then ["---+", " "]
|
353
|
+
when 6 then [" ", " "]
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
358
|
+
ary.map {|line| line.transpose }.flatten(1)[0..-2].each do |line|
|
359
|
+
puts line.join.rstrip[1..-1]
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
def find_loops(solution, field)
|
364
|
+
solution = solution.map {|line| line.dup }
|
365
|
+
field.each_with_index do |line, y|
|
366
|
+
line.each_with_index do |num, x|
|
367
|
+
next unless num
|
368
|
+
xo, yo = DIR[solution[y][x]]
|
369
|
+
solution[y][x] = nil
|
370
|
+
find_loops_aux(solution, field, x + xo, y + yo)
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
loops = []
|
375
|
+
solution.each_with_index do |line, y|
|
376
|
+
line.each_with_index do |c, x|
|
377
|
+
next if !c || c == 6
|
378
|
+
loops << find_loops_aux(solution, field, x, y)
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
loops
|
383
|
+
end
|
384
|
+
|
385
|
+
|
386
|
+
def find_loops_aux(solution, field, x, y)
|
387
|
+
ary = []
|
388
|
+
while !field[y][x]
|
389
|
+
num = solution[y][x]
|
390
|
+
ary << [x, y, num] if num
|
391
|
+
solution[y][x] = nil
|
392
|
+
case num
|
393
|
+
when 0 then solution[y - 1][x] ? y -= 1 : y += 1
|
394
|
+
when 1 then solution[y - 1][x] ? y -= 1 : x -= 1
|
395
|
+
when 2 then solution[y - 1][x] ? y -= 1 : x += 1
|
396
|
+
when 3 then solution[y + 1][x] ? y += 1 : x -= 1
|
397
|
+
when 4 then solution[y + 1][x] ? y += 1 : x += 1
|
398
|
+
when 5 then solution[y][x - 1] ? x -= 1 : x += 1
|
399
|
+
else break
|
400
|
+
end
|
401
|
+
end
|
402
|
+
ary
|
403
|
+
end
|
404
|
+
|
405
|
+
|
406
|
+
def add_loop_constraint(solver, vars, loops)
|
407
|
+
loops.each do |ary|
|
408
|
+
solver << ary.map {|x, y, c| vars[y][x].first[c] }
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
|
413
|
+
def solve(solver, vars, field, prog_msg, found_msg, not_found_msg)
|
414
|
+
trial = 0
|
415
|
+
loop do
|
416
|
+
trial += 1
|
417
|
+
puts "#{ prog_msg }... (trial #{ trial })"
|
418
|
+
puts "clauses : #{ solver.clause_size }"
|
419
|
+
|
420
|
+
start = Time.now
|
421
|
+
result = solver.solve
|
422
|
+
eplise = Time.now - start
|
423
|
+
puts "time: %.6f sec." % eplise
|
424
|
+
puts
|
425
|
+
unless result
|
426
|
+
puts not_found_msg
|
427
|
+
return false
|
428
|
+
end
|
429
|
+
|
430
|
+
puts "translating model into solution..."
|
431
|
+
solution = make_solution(solver, vars, field)
|
432
|
+
loops = find_loops(solution, field)
|
433
|
+
add_loop_constraint(solver, vars, loops)
|
434
|
+
|
435
|
+
if loops.empty?
|
436
|
+
puts found_msg
|
437
|
+
output_field(solution, field)
|
438
|
+
puts
|
439
|
+
return true
|
440
|
+
end
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
|
445
|
+
if ARGV.first == "-f"
|
446
|
+
$filled = true
|
447
|
+
ARGV.shift
|
448
|
+
end
|
449
|
+
if ARGV.first == "-b"
|
450
|
+
$filled = false
|
451
|
+
ARGV.shift
|
452
|
+
end
|
453
|
+
|
454
|
+
if ARGV.empty?
|
455
|
+
$stderr.puts <<END
|
456
|
+
usage: numberlink.rb [-f or -b] numberlink.sample
|
457
|
+
options:
|
458
|
+
-f search only filled solution (any blank cell has line) [default]
|
459
|
+
-b search any solution (blank cell may remain) (slowish)
|
460
|
+
END
|
461
|
+
exit 0
|
462
|
+
end
|
463
|
+
|
464
|
+
ARGV.each do |file|
|
465
|
+
field = parse_file(file)
|
466
|
+
|
467
|
+
solver = MiniSat::Solver.new
|
468
|
+
|
469
|
+
puts "defining SAT..."
|
470
|
+
vars = define_sat(solver, field)
|
471
|
+
puts "variables : #{ solver.var_size }"
|
472
|
+
puts
|
473
|
+
|
474
|
+
str = $filled ? "(filled) solution" : "solution"
|
475
|
+
|
476
|
+
prog_msg = "solving SAT"
|
477
|
+
found_msg = "#{ str } found."
|
478
|
+
not_found_msg = "unsolvable."
|
479
|
+
solve(solver, vars, field, prog_msg, found_msg, not_found_msg) or exit 1
|
480
|
+
|
481
|
+
add_constraint(solver, vars)
|
482
|
+
|
483
|
+
prog_msg = "finding different #{ str }"
|
484
|
+
found_msg = "different #{ str } found."
|
485
|
+
not_found_msg = "different #{ str } not found."
|
486
|
+
solve(solver, vars, field, prog_msg, found_msg, not_found_msg) and exit 1
|
487
|
+
puts
|
488
|
+
puts
|
489
|
+
end
|