ruby-minisat 1.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|