z3 0.0.0
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.
- checksums.yaml +7 -0
- data/README.md +27 -0
- data/examples/algebra_problems +148 -0
- data/examples/basic_int_math +30 -0
- data/examples/basic_logic +41 -0
- data/examples/geometry_problem +40 -0
- data/examples/kinematics_problems +219 -0
- data/examples/light_up_solver +105 -0
- data/examples/minisudoku_solver +64 -0
- data/examples/selfref_solver +370 -0
- data/examples/sudoku_solver +67 -0
- data/examples/verbal_arithmetic +47 -0
- data/lib/z3/ast.rb +302 -0
- data/lib/z3/context.rb +10 -0
- data/lib/z3/func_decl.rb +31 -0
- data/lib/z3/low_level.rb +254 -0
- data/lib/z3/model.rb +49 -0
- data/lib/z3/solver.rb +68 -0
- data/lib/z3/sort.rb +33 -0
- data/lib/z3/very_low_level.rb +89 -0
- data/lib/z3.rb +43 -0
- data/spec/ast_spec.rb +172 -0
- data/spec/integration/algebra_problems_spec.rb +30 -0
- data/spec/integration/bagic_int_math_spec.rb +14 -0
- data/spec/integration/basic_logic_spec.rb +15 -0
- data/spec/integration/geometry_problem_spec.rb +17 -0
- data/spec/integration/kinematics_problems_spec.rb +54 -0
- data/spec/integration/light_up_spec.rb +14 -0
- data/spec/integration/minisudoku_spec.rb +13 -0
- data/spec/integration/selfref_spec.rb +27 -0
- data/spec/integration/sudoku_spec.rb +16 -0
- data/spec/integration/verbal_arithmetic_spec.rb +10 -0
- data/spec/model_spec.rb +37 -0
- data/spec/solver_spec.rb +22 -0
- data/spec/sort_spec.rb +22 -0
- data/spec/spec_helper.rb +103 -0
- data/spec/z3_spec.rb +5 -0
- metadata +81 -0
@@ -0,0 +1,370 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative "../lib/z3"
|
4
|
+
|
5
|
+
class SelfRefPuzzleSolver
|
6
|
+
attr_reader :q, :a
|
7
|
+
attr_reader :a_answers, :b_answers, :c_answers, :d_answers, :e_answers, :cons_answers
|
8
|
+
def initialize
|
9
|
+
@solver = Z3::Solver.new
|
10
|
+
@q = {}
|
11
|
+
@a = {}
|
12
|
+
(1..20).each do |i|
|
13
|
+
@q[i] = Z3::Ast.int("q#{i}")
|
14
|
+
assert @q[i] >= 1
|
15
|
+
assert @q[i] <= 5
|
16
|
+
@a[i] = {}
|
17
|
+
(1..5).each do |j|
|
18
|
+
@a[i][j] = Z3::Ast.int("a#{i},#{' ABCDE'[j]}")
|
19
|
+
assert (@a[i][j] == 0) == (@q[i] != j)
|
20
|
+
assert (@a[i][j] == 1) == (@q[i] == j)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def assert(ast)
|
26
|
+
@solver.assert(ast)
|
27
|
+
end
|
28
|
+
|
29
|
+
def cons_in(*ary)
|
30
|
+
Z3::Ast.or(*ary.map{|i| cons_answers == i})
|
31
|
+
end
|
32
|
+
|
33
|
+
def solve!
|
34
|
+
@a_answers = Z3::Ast.add(*(1..20).map{|i| @a[i][1]})
|
35
|
+
@b_answers = Z3::Ast.add(*(1..20).map{|i| @a[i][2]})
|
36
|
+
@c_answers = Z3::Ast.add(*(1..20).map{|i| @a[i][3]})
|
37
|
+
@d_answers = Z3::Ast.add(*(1..20).map{|i| @a[i][4]})
|
38
|
+
@e_answers = Z3::Ast.add(*(1..20).map{|i| @a[i][5]})
|
39
|
+
@cons_answers = b_answers + c_answers + d_answers
|
40
|
+
|
41
|
+
# Question 1
|
42
|
+
assert (q[1] == 1) == (q[1] == 2)
|
43
|
+
assert (q[1] == 2) == Z3::Ast.and(q[1] != 2, q[2] == 2)
|
44
|
+
assert (q[1] == 3) == Z3::Ast.and(q[1] != 2, q[2] != 2, q[3] == 2)
|
45
|
+
assert (q[1] == 4) == Z3::Ast.and(q[1] != 2, q[2] != 2, q[3] != 2, q[4] == 2)
|
46
|
+
assert (q[1] == 5) == Z3::Ast.and(q[1] != 2, q[2] != 2, q[3] != 2, q[4] != 2, q[5] == 2)
|
47
|
+
|
48
|
+
# Question 2
|
49
|
+
assert q[ 1] != q[ 2]
|
50
|
+
assert q[ 2] != q[ 3]
|
51
|
+
assert q[ 3] != q[ 4]
|
52
|
+
assert q[ 4] != q[ 5]
|
53
|
+
assert q[ 5] != q[ 6]
|
54
|
+
assert (q[ 6] == q[ 7]) == (q[2] == 1)
|
55
|
+
assert (q[ 7] == q[ 8]) == (q[2] == 2)
|
56
|
+
assert (q[ 8] == q[ 9]) == (q[2] == 3)
|
57
|
+
assert (q[ 9] == q[10]) == (q[2] == 4)
|
58
|
+
assert (q[10] == q[11]) == (q[2] == 5)
|
59
|
+
assert q[11] != q[12]
|
60
|
+
assert q[12] != q[13]
|
61
|
+
assert q[13] != q[14]
|
62
|
+
assert q[14] != q[15]
|
63
|
+
assert q[15] != q[16]
|
64
|
+
assert q[16] != q[17]
|
65
|
+
assert q[17] != q[18]
|
66
|
+
assert q[18] != q[19]
|
67
|
+
assert q[19] != q[20]
|
68
|
+
|
69
|
+
# Question 3
|
70
|
+
assert (e_answers == 0) == (q[3] == 1)
|
71
|
+
assert (e_answers == 1) == (q[3] == 2)
|
72
|
+
assert (e_answers == 2) == (q[3] == 3)
|
73
|
+
assert (e_answers == 3) == (q[3] == 4)
|
74
|
+
assert (e_answers == 4) == (q[3] == 5)
|
75
|
+
|
76
|
+
# Question 4
|
77
|
+
assert (a_answers == 4) == (q[4] == 1)
|
78
|
+
assert (a_answers == 5) == (q[4] == 2)
|
79
|
+
assert (a_answers == 6) == (q[4] == 3)
|
80
|
+
assert (a_answers == 7) == (q[4] == 4)
|
81
|
+
assert (a_answers == 8) == (q[4] == 5)
|
82
|
+
|
83
|
+
# Question 5
|
84
|
+
assert Z3::Ast.implies(q[5] == 1, q[5] == q[1])
|
85
|
+
assert Z3::Ast.implies(q[5] == 2, q[5] == q[2])
|
86
|
+
assert Z3::Ast.implies(q[5] == 3, q[5] == q[3])
|
87
|
+
assert Z3::Ast.implies(q[5] == 4, q[5] == q[4])
|
88
|
+
assert Z3::Ast.implies(q[5] == 5, q[5] == q[5])
|
89
|
+
|
90
|
+
# Question 6
|
91
|
+
assert (q[17] == 3) == (q[6] == 1)
|
92
|
+
assert (q[17] == 4) == (q[6] == 2)
|
93
|
+
assert (q[17] == 5) == (q[6] == 3)
|
94
|
+
assert Z3::Ast.or(q[17] == 1, q[17] == 2) == (q[6] == 4)
|
95
|
+
assert q[6] != 5
|
96
|
+
|
97
|
+
# Question 7
|
98
|
+
assert Z3::Ast.or(q[7] - q[8] == 4, q[8] - q[7] == 4) == (q[7] == 1)
|
99
|
+
assert Z3::Ast.or(q[7] - q[8] == 3, q[8] - q[7] == 3) == (q[7] == 2)
|
100
|
+
assert Z3::Ast.or(q[7] - q[8] == 2, q[8] - q[7] == 2) == (q[7] == 3)
|
101
|
+
assert Z3::Ast.or(q[7] - q[8] == 1, q[8] - q[7] == 1) == (q[7] == 4)
|
102
|
+
assert Z3::Ast.or(q[7] - q[8] == 0, q[8] - q[7] == 0) == (q[7] == 5)
|
103
|
+
|
104
|
+
# Question 8
|
105
|
+
assert (a_answers + e_answers == 4) == (q[8] == 1)
|
106
|
+
assert (a_answers + e_answers == 5) == (q[8] == 2)
|
107
|
+
assert (a_answers + e_answers == 6) == (q[8] == 3)
|
108
|
+
assert (a_answers + e_answers == 7) == (q[8] == 4)
|
109
|
+
assert (a_answers + e_answers == 8) == (q[8] == 5)
|
110
|
+
|
111
|
+
# Question 9
|
112
|
+
assert (q[10] == q[9]) == (q[9] == 1)
|
113
|
+
assert Z3::Ast.and(q[10] != q[9], q[11] == q[9]) == (q[9] == 2)
|
114
|
+
assert Z3::Ast.and(q[10] != q[9], q[11] != q[9], q[12] == q[9]) == (q[9] == 3)
|
115
|
+
assert Z3::Ast.and(q[10] != q[9], q[11] != q[9], q[12] != q[9], q[13] == q[9]) == (q[9] == 4)
|
116
|
+
assert Z3::Ast.and(q[10] != q[9], q[11] != q[9], q[12] != q[9], q[13] != q[9], q[14] == q[9]) == (q[9] == 5)
|
117
|
+
|
118
|
+
# Question 10
|
119
|
+
assert (q[16] == 4) == (q[10] == 1)
|
120
|
+
assert (q[16] == 1) == (q[10] == 2)
|
121
|
+
assert (q[16] == 5) == (q[10] == 3)
|
122
|
+
assert (q[16] == 2) == (q[10] == 4)
|
123
|
+
assert (q[16] == 3) == (q[10] == 5)
|
124
|
+
|
125
|
+
# Question 11
|
126
|
+
prec_b_answers = Z3::Ast.add(*(1..10).map{|i| @a[i][2]})
|
127
|
+
assert (prec_b_answers == 0) == (q[11] == 1)
|
128
|
+
assert (prec_b_answers == 1) == (q[11] == 2)
|
129
|
+
assert (prec_b_answers == 2) == (q[11] == 3)
|
130
|
+
assert (prec_b_answers == 3) == (q[11] == 4)
|
131
|
+
assert (prec_b_answers == 4) == (q[11] == 5)
|
132
|
+
|
133
|
+
# Question 12
|
134
|
+
assert Z3::Ast.implies(q[12] == 1, cons_in(2,4,6,8,10,12,14,16,18,20))
|
135
|
+
assert Z3::Ast.implies(q[12] == 2, cons_in(1,3,5,7,9,11,13,15,17,19))
|
136
|
+
assert Z3::Ast.implies(q[12] == 3, cons_in(1,4,9,16))
|
137
|
+
assert Z3::Ast.implies(q[12] == 4, cons_in(2,3,5,7,11,13,17,19))
|
138
|
+
assert Z3::Ast.implies(q[12] == 5, cons_in(5,10,15,20))
|
139
|
+
|
140
|
+
# Question 13
|
141
|
+
assert q[1] != 1
|
142
|
+
assert q[3] != 1
|
143
|
+
assert q[5] != 1
|
144
|
+
assert q[7] != 1
|
145
|
+
assert (q[ 9] == 1) == (q[13] == 1)
|
146
|
+
assert (q[11] == 1) == (q[13] == 2)
|
147
|
+
assert (q[13] == 1) == (q[13] == 3)
|
148
|
+
assert (q[15] == 1) == (q[13] == 4)
|
149
|
+
assert (q[17] == 1) == (q[13] == 5)
|
150
|
+
assert q[19] != 1
|
151
|
+
|
152
|
+
# Question 14
|
153
|
+
assert (d_answers == 6) == (q[4] == 1)
|
154
|
+
assert (d_answers == 7) == (q[4] == 2)
|
155
|
+
assert (d_answers == 8) == (q[4] == 3)
|
156
|
+
assert (d_answers == 9) == (q[4] == 4)
|
157
|
+
assert (d_answers == 10) == (q[4] == 5)
|
158
|
+
|
159
|
+
# Question 15
|
160
|
+
assert q[15] == q[12]
|
161
|
+
|
162
|
+
# Question 16
|
163
|
+
assert (q[10] == 4) == (q[16] == 1)
|
164
|
+
assert (q[10] == 3) == (q[16] == 2)
|
165
|
+
assert (q[10] == 2) == (q[16] == 3)
|
166
|
+
assert (q[10] == 1) == (q[16] == 4)
|
167
|
+
assert (q[10] == 5) == (q[16] == 5)
|
168
|
+
|
169
|
+
# Question 17
|
170
|
+
assert (q[6] == 3) == (q[17] == 1)
|
171
|
+
assert (q[6] == 4) == (q[17] == 2)
|
172
|
+
assert (q[6] == 5) == (q[17] == 3)
|
173
|
+
assert Z3::Ast.and(q[6] != 3, q[6] != 4, q[6] != 5) == (q[17] == 4)
|
174
|
+
assert q[17] != 5
|
175
|
+
|
176
|
+
# Question 18
|
177
|
+
assert (a_answers == b_answers) == (q[18] == 1)
|
178
|
+
assert (a_answers == c_answers) == (q[18] == 2)
|
179
|
+
assert (a_answers == d_answers) == (q[18] == 3)
|
180
|
+
assert (a_answers == e_answers) == (q[18] == 4)
|
181
|
+
assert Z3::Ast.and(
|
182
|
+
a_answers != b_answers,
|
183
|
+
a_answers != c_answers,
|
184
|
+
a_answers != d_answers,
|
185
|
+
a_answers != e_answers
|
186
|
+
) == (q[18] == 5)
|
187
|
+
|
188
|
+
# Question 19
|
189
|
+
assert q[19] == q[19]
|
190
|
+
|
191
|
+
# Question 20
|
192
|
+
assert q[20] == 5
|
193
|
+
|
194
|
+
# Print solutions
|
195
|
+
if @solver.check == :sat
|
196
|
+
model = @solver.model
|
197
|
+
(1..20).each do |i|
|
198
|
+
a = model[q[i]].to_s.to_i
|
199
|
+
puts "Q%2d: %s" % [i, " ABCDE"[a]]
|
200
|
+
end
|
201
|
+
else
|
202
|
+
puts "failed to solve"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
|
208
|
+
SelfRefPuzzleSolver.new.solve!
|
209
|
+
|
210
|
+
__END__
|
211
|
+
http://faculty.uml.edu/jpropp/srat-Q.txt
|
212
|
+
|
213
|
+
SELF-REFERENTIAL APTITUDE TEST, by Jim Propp (jimpropp at gmaildotcom)
|
214
|
+
|
215
|
+
The solution to the following puzzle is unique; in some cases the
|
216
|
+
knowledge that the solution is unique may actually give you a short-cut
|
217
|
+
to finding the answer to a particular question. (Thanks to Andy Latto
|
218
|
+
for bringing this subtlety to my attention.)
|
219
|
+
|
220
|
+
I should mention that if you don't agree with me about the answer to #20,
|
221
|
+
you will get a different solution to the puzzle than the one I had in mind.
|
222
|
+
But I should also mention that if you don't agree with me about the answer
|
223
|
+
to #20, you are just plain wrong. :-)
|
224
|
+
|
225
|
+
You may now begin work.
|
226
|
+
|
227
|
+
|
228
|
+
1. The first question whose answer is B is question
|
229
|
+
(A) 1
|
230
|
+
(B) 2
|
231
|
+
(C) 3
|
232
|
+
(D) 4
|
233
|
+
(E) 5
|
234
|
+
|
235
|
+
2. The only two consecutive questions with identical answers are questions
|
236
|
+
(A) 6 and 7
|
237
|
+
(B) 7 and 8
|
238
|
+
(C) 8 and 9
|
239
|
+
(D) 9 and 10
|
240
|
+
(E) 10 and 11
|
241
|
+
|
242
|
+
3. The number of questions with the answer E is
|
243
|
+
(A) 0
|
244
|
+
(B) 1
|
245
|
+
(C) 2
|
246
|
+
(D) 3
|
247
|
+
(E) 4
|
248
|
+
|
249
|
+
4. The number of questions with the answer A is
|
250
|
+
(A) 4
|
251
|
+
(B) 5
|
252
|
+
(C) 6
|
253
|
+
(D) 7
|
254
|
+
(E) 8
|
255
|
+
|
256
|
+
5. The answer to this question is the same as the answer to question
|
257
|
+
(A) 1
|
258
|
+
(B) 2
|
259
|
+
(C) 3
|
260
|
+
(D) 4
|
261
|
+
(E) 5
|
262
|
+
|
263
|
+
6. The answer to question 17 is
|
264
|
+
(A) C
|
265
|
+
(B) D
|
266
|
+
(C) E
|
267
|
+
(D) none of the above
|
268
|
+
(E) all of the above
|
269
|
+
|
270
|
+
7. Alphabetically, the answer to this question and the answer to the
|
271
|
+
following question are
|
272
|
+
(A) 4 apart
|
273
|
+
(B) 3 apart
|
274
|
+
(C) 2 apart
|
275
|
+
(D) 1 apart
|
276
|
+
(E) the same
|
277
|
+
|
278
|
+
8. The number of questions whose answers are vowels is
|
279
|
+
(A) 4
|
280
|
+
(B) 5
|
281
|
+
(C) 6
|
282
|
+
(D) 7
|
283
|
+
(E) 8
|
284
|
+
|
285
|
+
9. The next question with the same answer as this one is question
|
286
|
+
(A) 10
|
287
|
+
(B) 11
|
288
|
+
(C) 12
|
289
|
+
(D) 13
|
290
|
+
(E) 14
|
291
|
+
|
292
|
+
10. The answer to question 16 is
|
293
|
+
(A) D
|
294
|
+
(B) A
|
295
|
+
(C) E
|
296
|
+
(D) B
|
297
|
+
(E) C
|
298
|
+
|
299
|
+
11. The number of questions preceding this one with the answer B is
|
300
|
+
(A) 0
|
301
|
+
(B) 1
|
302
|
+
(C) 2
|
303
|
+
(D) 3
|
304
|
+
(E) 4
|
305
|
+
|
306
|
+
12. The number of questions whose answer is a consonant is
|
307
|
+
(A) an even number
|
308
|
+
(B) an odd number
|
309
|
+
(C) a perfect square
|
310
|
+
(D) a prime
|
311
|
+
(E) divisible by 5
|
312
|
+
|
313
|
+
13. The only odd-numbered problem with answer A is
|
314
|
+
(A) 9
|
315
|
+
(B) 11
|
316
|
+
(C) 13
|
317
|
+
(D) 15
|
318
|
+
(E) 17
|
319
|
+
|
320
|
+
14. The number of questions with answer D is
|
321
|
+
(A) 6
|
322
|
+
(B) 7
|
323
|
+
(C) 8
|
324
|
+
(D) 9
|
325
|
+
(E) 10
|
326
|
+
|
327
|
+
15. The answer to question 12 is
|
328
|
+
(A) A
|
329
|
+
(B) B
|
330
|
+
(C) C
|
331
|
+
(D) D
|
332
|
+
(E) E
|
333
|
+
|
334
|
+
16. The answer to question 10 is
|
335
|
+
(A) D
|
336
|
+
(B) C
|
337
|
+
(C) B
|
338
|
+
(D) A
|
339
|
+
(E) E
|
340
|
+
|
341
|
+
17. The answer to question 6 is
|
342
|
+
(A) C
|
343
|
+
(B) D
|
344
|
+
(C) E
|
345
|
+
(D) none of the above
|
346
|
+
(E) all of the above
|
347
|
+
|
348
|
+
18. The number of questions with answer A equals the number of questions
|
349
|
+
with answer
|
350
|
+
(A) B
|
351
|
+
(B) C
|
352
|
+
(C) D
|
353
|
+
(D) E
|
354
|
+
(E) none of the above
|
355
|
+
|
356
|
+
19. The answer to this question is:
|
357
|
+
(A) A
|
358
|
+
(B) B
|
359
|
+
(C) C
|
360
|
+
(D) D
|
361
|
+
(E) E
|
362
|
+
|
363
|
+
20. Standardized test is to intelligence as barometer is to
|
364
|
+
(A) temperature (only)
|
365
|
+
(B) wind-velocity (only)
|
366
|
+
(C) latitude (only)
|
367
|
+
(D) longitude (only)
|
368
|
+
(E) temperature, wind-velocity, latitude, and longitude
|
369
|
+
|
370
|
+
( to go to the main SRAT page, go to jamespropp.org/srat.html )
|
@@ -0,0 +1,67 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative "../lib/z3"
|
4
|
+
|
5
|
+
class SudokuSolver
|
6
|
+
def initialize(data)
|
7
|
+
@data = data
|
8
|
+
@solver = Z3::Solver.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def solve!
|
12
|
+
@cells = (0..8).map do |j|
|
13
|
+
(0..8).map do |i|
|
14
|
+
cell_var(@data[j][i], i, j)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
@cells.each do |row|
|
19
|
+
@solver.assert Z3::Ast.distinct(*row)
|
20
|
+
end
|
21
|
+
@cells.transpose.each do |column|
|
22
|
+
@solver.assert Z3::Ast.distinct(*column)
|
23
|
+
end
|
24
|
+
@cells.each_slice(3) do |rows|
|
25
|
+
rows.transpose.each_slice(3) do |square|
|
26
|
+
@solver.assert Z3::Ast.distinct(*square.flatten)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
if @solver.check == :sat
|
31
|
+
@model = @solver.model
|
32
|
+
print_answer!
|
33
|
+
else
|
34
|
+
puts "failed to solve"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def cell_var(cell, i, j)
|
41
|
+
v = Z3::Ast.int("cell[#{i+1},#{j+1}]")
|
42
|
+
@solver.assert v >= 1
|
43
|
+
@solver.assert v <= 9
|
44
|
+
@solver.assert v == cell if cell != nil
|
45
|
+
v
|
46
|
+
end
|
47
|
+
|
48
|
+
def print_answer!
|
49
|
+
@cells.each do |row|
|
50
|
+
puts row.map{|v| @model[v]}.join(" ")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
_ = nil
|
56
|
+
sudoku = SudokuSolver.new([
|
57
|
+
[_, 6, _, 5, _, 9, _, 4, _],
|
58
|
+
[9, 2, _, _, _, _, _, 7, 6],
|
59
|
+
[_, _, 1, _, _, _, 9, _, _],
|
60
|
+
[7, _, _, 6, _, 3, _, _, 9],
|
61
|
+
[_, _, _, _, _, _, _, _, _],
|
62
|
+
[3, _, _, 4, _, 1, _, _, 7],
|
63
|
+
[_, _, 6, _, _, _, 7, _, _],
|
64
|
+
[2, 4, _, _, _, _, _, 6, 5],
|
65
|
+
[_, 9, _, 1, _, 8, _, 3, _],
|
66
|
+
])
|
67
|
+
sudoku.solve!
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative "../lib/z3"
|
4
|
+
|
5
|
+
class VerbalArithmetic
|
6
|
+
def initialize(a, b, c)
|
7
|
+
@solver = Z3::Solver.new
|
8
|
+
@vars = Hash.new do |ht,name|
|
9
|
+
v = Z3::Ast.int(name)
|
10
|
+
@solver.assert v >= 0
|
11
|
+
@solver.assert v <= 9
|
12
|
+
ht[name] = v
|
13
|
+
end
|
14
|
+
@a = a.chars.map{|v| @vars[v]}
|
15
|
+
@b = b.chars.map{|v| @vars[v]}
|
16
|
+
@c = c.chars.map{|v| @vars[v]}
|
17
|
+
end
|
18
|
+
|
19
|
+
def solve!
|
20
|
+
@solver.assert @a[0] != 0
|
21
|
+
@solver.assert @b[0] != 0
|
22
|
+
@solver.assert @c[0] != 0
|
23
|
+
@solver.assert word_value(@a) + word_value(@b) == word_value(@c)
|
24
|
+
@solver.assert Z3::Ast.distinct(*@vars.values)
|
25
|
+
|
26
|
+
if @solver.check == :sat
|
27
|
+
@model = @solver.model
|
28
|
+
print_answer!
|
29
|
+
else
|
30
|
+
puts "failed to solve"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def word_value(word)
|
37
|
+
word.inject(0){|x,y| 10*x+y}
|
38
|
+
end
|
39
|
+
|
40
|
+
def print_answer!
|
41
|
+
[@a,@b,@c].each do |word|
|
42
|
+
p word.map{|v| [v.to_s, @model[v].to_s.to_i]}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
VerbalArithmetic.new("SEND", "MORE", "MONEY").solve!
|