z3 0.0.20160221 → 0.0.20160323
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -1
- data/examples/algebra_problems +24 -24
- data/examples/basic_int_math +8 -8
- data/examples/basic_logic +8 -8
- data/examples/bit_tricks +161 -0
- data/examples/bridges_solver +1 -1
- data/examples/clogic_puzzle_solver +135 -0
- data/examples/four_hackers_puzzle +194 -0
- data/examples/geometry_problem +11 -11
- data/examples/kakuro_solver +3 -3
- data/examples/kinematics_problems +37 -37
- data/examples/letter_connections_solver +11 -11
- data/examples/light_up_solver +5 -5
- data/examples/minisudoku_solver +4 -4
- data/examples/selfref_solver +35 -35
- data/examples/sudoku_solver +4 -4
- data/examples/verbal_arithmetic +2 -2
- data/lib/z3/exception.rb +25 -0
- data/lib/z3/func_decl.rb +7 -7
- data/lib/z3/interface.rb +255 -0
- data/lib/z3/low_level.rb +4 -6
- data/lib/z3/low_level_auto.rb +1551 -1547
- data/lib/z3/model.rb +3 -2
- data/lib/z3/solver.rb +65 -54
- data/lib/z3/sort/bitvec_sort.rb +40 -0
- data/lib/z3/sort/bool_sort.rb +31 -0
- data/lib/z3/sort/int_sort.rb +21 -0
- data/lib/z3/sort/real_sort.rb +36 -0
- data/lib/z3/sort/sort.rb +76 -0
- data/lib/z3/value/arith_value.rb +53 -0
- data/lib/z3/value/bitvec_value.rb +67 -0
- data/lib/z3/value/bool_value.rb +29 -0
- data/lib/z3/value/int_value.rb +7 -0
- data/lib/z3/value/real_value.rb +7 -0
- data/lib/z3/value/value.rb +48 -0
- data/lib/z3/very_low_level.rb +28 -45
- data/lib/z3/very_low_level_auto.rb +518 -516
- data/lib/z3.rb +23 -33
- data/spec/integration/bit_tricks_spec.rb +21 -0
- data/spec/model_spec.rb +9 -9
- data/spec/solver_spec.rb +2 -2
- data/spec/sort_spec.rb +38 -13
- data/spec/{ast_spec.rb → value_spec.rb} +60 -57
- metadata +21 -6
- data/lib/z3/ast.rb +0 -302
- data/lib/z3/sort.rb +0 -33
- /data/spec/integration/{bagic_int_math_spec.rb → basic_int_math_spec.rb} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ec7feb43474477a1c3a7220fbbd5c6e11246cd2
|
4
|
+
data.tar.gz: 687aedb2c8aaeca944108d4361459bba5ba08eb5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e641cf575e0810de111a96f394747b1316dc2f9cebd63c7a52390c2439c7836abf1660d67b52998f5e4a048fea74a569121e7f9fd9e4a2e32bce82367082362
|
7
|
+
data.tar.gz: 9d1c79300d21645a5ed1e121a8f069fd0a4504c5731ff07c5e5f6a6727647c94ae64fb885c4f4e5bfb2b4641183b2e697f8128d3f66f784cdc9ab6dcce3361fe
|
data/README.md
CHANGED
@@ -8,10 +8,12 @@ It's in extremely early stages of development. Pull requests always welcome.
|
|
8
8
|
|
9
9
|
The rest of `Z3` is high level API, but the interface is extremely unstable at this point, and it's pretty much guaranteed to change many times. Check specs or `examples/` directory for usage.
|
10
10
|
|
11
|
-
You can use most Ruby operators to construct
|
11
|
+
You can use most Ruby operators to construct Z3 expressions, but use `~ | &` instead of `! || &&` for boolean operators. They unfortunately have wrong operator precedence so you'll need to use some extra parentheses.
|
12
12
|
|
13
13
|
As for API internals, attributes starting with `_` are FFI internals you shouldn't touch, other attributes are generally legitimate Ruby objects.
|
14
14
|
|
15
|
+
Bit vectors are treated as signed by default. [well, mostly, more systematic treatment of this is on TODO list]
|
16
|
+
|
15
17
|
### Requirements
|
16
18
|
|
17
19
|
To use it, you'll need to install `z3`. On OSX that would be:
|
data/examples/algebra_problems
CHANGED
@@ -22,7 +22,7 @@ end
|
|
22
22
|
|
23
23
|
class AlgebraProblem01 < AlgebraProblem
|
24
24
|
def solve!
|
25
|
-
x = Z3
|
25
|
+
x = Z3.Real("x")
|
26
26
|
solver.assert 5*(-3*x - 2) - (x - 3) == -4*(4*x + 5) + 13
|
27
27
|
print_solution! "01"
|
28
28
|
# No nice way to say x is unconstrained
|
@@ -31,17 +31,17 @@ end
|
|
31
31
|
|
32
32
|
class AlgebraProblem03 < AlgebraProblem
|
33
33
|
def declare_abs(var, expr)
|
34
|
-
solver.assert Z3
|
35
|
-
Z3
|
36
|
-
Z3
|
34
|
+
solver.assert Z3.Or(
|
35
|
+
Z3.And(var == expr, expr >= 0),
|
36
|
+
Z3.And(var == -expr, expr <= 0)
|
37
37
|
)
|
38
38
|
end
|
39
39
|
|
40
40
|
def solve!
|
41
|
-
x = Z3
|
42
|
-
xm2abs = Z3
|
41
|
+
x = Z3.Real("x")
|
42
|
+
xm2abs = Z3.Real("|x-2|")
|
43
43
|
declare_abs(xm2abs, x-2)
|
44
|
-
m6abs = Z3
|
44
|
+
m6abs = Z3.Real("|-6|")
|
45
45
|
declare_abs(m6abs, -6)
|
46
46
|
solver.assert x < 2
|
47
47
|
solver.assert xm2abs == 4*m6abs
|
@@ -56,11 +56,11 @@ class AlgebraProblem04 < AlgebraProblem
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def solve!
|
59
|
-
ax = Z3
|
60
|
-
ay = Z3
|
61
|
-
bx = Z3
|
62
|
-
by = Z3
|
63
|
-
a_b = Z3
|
59
|
+
ax = Z3.Real("ax")
|
60
|
+
ay = Z3.Real("ay")
|
61
|
+
bx = Z3.Real("bx")
|
62
|
+
by = Z3.Real("by")
|
63
|
+
a_b = Z3.Real("|a-b|")
|
64
64
|
declare_distance(a_b, ax, ay, bx, by)
|
65
65
|
solver.assert ax == -4
|
66
66
|
solver.assert ay == -5
|
@@ -72,8 +72,8 @@ end
|
|
72
72
|
|
73
73
|
class AlgebraProblem05 < AlgebraProblem
|
74
74
|
def solve!
|
75
|
-
x = Z3
|
76
|
-
y = Z3
|
75
|
+
x = Z3.Real("x")
|
76
|
+
y = Z3.Real("y")
|
77
77
|
solver.assert 2*x - 4*y == 9
|
78
78
|
solver.assert y == 0
|
79
79
|
print_solution! "05"
|
@@ -86,11 +86,11 @@ class AlgebraProblem06 < AlgebraProblem
|
|
86
86
|
end
|
87
87
|
|
88
88
|
def solve!
|
89
|
-
x1 = Z3
|
90
|
-
y1 = Z3
|
91
|
-
x2 = Z3
|
92
|
-
y2 = Z3
|
93
|
-
answer = Z3
|
89
|
+
x1 = Z3.Real("x1")
|
90
|
+
y1 = Z3.Real("y1")
|
91
|
+
x2 = Z3.Real("x2")
|
92
|
+
y2 = Z3.Real("y2")
|
93
|
+
answer = Z3.Real("answer")
|
94
94
|
solver.assert x2 == 2
|
95
95
|
solver.assert x1 == 1
|
96
96
|
declare_f(x1, y1)
|
@@ -102,15 +102,15 @@ end
|
|
102
102
|
|
103
103
|
class AlgebraProblem10 < AlgebraProblem
|
104
104
|
def declare_abs(var, expr)
|
105
|
-
solver.assert Z3
|
106
|
-
Z3
|
107
|
-
Z3
|
105
|
+
solver.assert Z3.Or(
|
106
|
+
Z3.And(var == expr, expr >= 0),
|
107
|
+
Z3.And(var == -expr, expr <= 0)
|
108
108
|
)
|
109
109
|
end
|
110
110
|
|
111
111
|
def solve!
|
112
|
-
x = Z3
|
113
|
-
y = Z3
|
112
|
+
x = Z3.Real("x")
|
113
|
+
y = Z3.Real("|-2x + 2|")
|
114
114
|
declare_abs(y, -2*x + 2)
|
115
115
|
solver.assert y - 3 == -3
|
116
116
|
print_solution! "10"
|
data/examples/basic_int_math
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
require_relative "../lib/z3"
|
4
4
|
|
5
5
|
def check_multiplication_laws_1
|
6
|
-
a = Z3
|
7
|
-
b = Z3
|
6
|
+
a = Z3.Int("a")
|
7
|
+
b = Z3.Int("b")
|
8
8
|
solver = Z3::Solver.new
|
9
9
|
puts "Checking if (a+b)(a-b)==a*a-b*b"
|
10
10
|
solver.prove!(
|
@@ -13,17 +13,17 @@ def check_multiplication_laws_1
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def check_inequalities
|
16
|
-
a = Z3
|
17
|
-
b = Z3
|
16
|
+
a = Z3.Int("a")
|
17
|
+
b = Z3.Int("b")
|
18
18
|
solver = Z3::Solver.new
|
19
19
|
puts "Checking if a+b >= a"
|
20
|
-
solver.prove!
|
20
|
+
solver.prove! a+b >= a
|
21
21
|
|
22
22
|
solver = Z3::Solver.new
|
23
|
-
solver.assert
|
24
|
-
solver.assert
|
23
|
+
solver.assert a >= 0
|
24
|
+
solver.assert b >= 0
|
25
25
|
puts "Checking if a+b >= a if a,b >= 0"
|
26
|
-
solver.prove!
|
26
|
+
solver.prove! a+b >= a
|
27
27
|
end
|
28
28
|
|
29
29
|
check_multiplication_laws_1
|
data/examples/basic_logic
CHANGED
@@ -3,16 +3,16 @@
|
|
3
3
|
require_relative "../lib/z3"
|
4
4
|
|
5
5
|
def check_if_true_is_true
|
6
|
-
a = Z3
|
7
|
-
b = Z3
|
6
|
+
a = Z3.True
|
7
|
+
b = Z3.True
|
8
8
|
solver = Z3::Solver.new
|
9
9
|
puts "Checking if true == true"
|
10
10
|
solver.prove!(a == b)
|
11
11
|
end
|
12
12
|
|
13
13
|
def check_if_true_is_false
|
14
|
-
a = Z3
|
15
|
-
b = Z3
|
14
|
+
a = Z3.True
|
15
|
+
b = Z3.False
|
16
16
|
solver = Z3::Solver.new
|
17
17
|
puts "Checking if true == false"
|
18
18
|
solver.prove!(a==b)
|
@@ -20,16 +20,16 @@ end
|
|
20
20
|
|
21
21
|
# We prove it by checking that negation is unsatisfiable
|
22
22
|
def check_de_morgan_law_1
|
23
|
-
a = Z3
|
24
|
-
b = Z3
|
23
|
+
a = Z3.Bool("a")
|
24
|
+
b = Z3.Bool("b")
|
25
25
|
solver = Z3::Solver.new
|
26
26
|
puts "Proving ~(a & b) == (~a | ~b)"
|
27
27
|
solver.prove!(~(a & b) == (~a | ~b))
|
28
28
|
end
|
29
29
|
|
30
30
|
def check_de_morgan_law_2
|
31
|
-
a = Z3
|
32
|
-
b = Z3
|
31
|
+
a = Z3.Bool("a")
|
32
|
+
b = Z3.Bool("b")
|
33
33
|
solver = Z3::Solver.new
|
34
34
|
puts "Proving ~(a | b) == (~a & ~b)"
|
35
35
|
solver.prove!(~(a | b) == (~a & ~b))
|
data/examples/bit_tricks
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative "../lib/z3"
|
4
|
+
|
5
|
+
def validate_sign_by_shift!
|
6
|
+
"""
|
7
|
+
sign = v >> (sizeof(int) * CHAR_BIT - 1);
|
8
|
+
"""
|
9
|
+
solver = Z3::Solver.new
|
10
|
+
v = Z3.Bitvec("v", 32)
|
11
|
+
s = v >> 31
|
12
|
+
puts "Validating sign trick:"
|
13
|
+
solver.prove! ((v < 0) & (s == -1)) | ((v >= 0) & (s == 0))
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate_opposite_sign_by_xor!
|
17
|
+
"""
|
18
|
+
int x, y; // input values to compare signs
|
19
|
+
bool f = ((x ^ y) < 0); // true iff x and y have opposite signs
|
20
|
+
"""
|
21
|
+
solver = Z3::Solver.new
|
22
|
+
x = Z3.Bitvec("x", 32)
|
23
|
+
y = Z3.Bitvec("y", 32)
|
24
|
+
f = (x^y) < 0
|
25
|
+
|
26
|
+
puts "Validating sign trick:"
|
27
|
+
solver.prove!(
|
28
|
+
Z3.Or(
|
29
|
+
Z3.And(x >= 0, y >= 0, f == false),
|
30
|
+
Z3.And(x < 0, y < 0, f == false),
|
31
|
+
Z3.And(x >= 0, y < 0, f == true),
|
32
|
+
Z3.And(x < 0, y >= 0, f == true),
|
33
|
+
)
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate_abs_without_branching_1!
|
38
|
+
"""
|
39
|
+
int v; // we want to find the absolute value of v
|
40
|
+
unsigned int r; // the result goes here
|
41
|
+
int const mask = v >> sizeof(int) * CHAR_BIT - 1;
|
42
|
+
r = (v + mask) ^ mask;
|
43
|
+
"""
|
44
|
+
solver = Z3::Solver.new
|
45
|
+
v = Z3.Bitvec("v", 32)
|
46
|
+
mask = v >> 31
|
47
|
+
r = (v + mask) ^ mask
|
48
|
+
puts "Validating abs without branching, version 1"
|
49
|
+
solver.prove!(
|
50
|
+
Z3.Or(
|
51
|
+
Z3.And(v >= 0, r==v),
|
52
|
+
Z3.And(v < 0, r==-v)
|
53
|
+
)
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
def validate_abs_without_branching_2!
|
58
|
+
"""
|
59
|
+
int v; // we want to find the absolute value of v
|
60
|
+
unsigned int r; // the result goes here
|
61
|
+
int const mask = v >> sizeof(int) * CHAR_BIT - 1;
|
62
|
+
r = (v ^ mask) - mask;
|
63
|
+
"""
|
64
|
+
solver = Z3::Solver.new
|
65
|
+
v = Z3.Bitvec("v", 32)
|
66
|
+
mask = v >> 31
|
67
|
+
r = (v^mask) - mask
|
68
|
+
puts "Validating abs without branching, version 2"
|
69
|
+
solver.prove!(
|
70
|
+
Z3.Or(
|
71
|
+
Z3.And(v >= 0, r==v),
|
72
|
+
Z3.And(v < 0, r==-v)
|
73
|
+
)
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
def c_boolean(solver, bool_expr, name)
|
78
|
+
expr_val = Z3.Bitvec(name, 32)
|
79
|
+
solver.assert(
|
80
|
+
Z3.Or(
|
81
|
+
Z3.And(bool_expr, expr_val == 1),
|
82
|
+
Z3.And(~bool_expr, expr_val == 0),
|
83
|
+
)
|
84
|
+
)
|
85
|
+
expr_val
|
86
|
+
end
|
87
|
+
|
88
|
+
def validate_min_without_branching!
|
89
|
+
"""
|
90
|
+
int x; // we want to find the minimum of x and y
|
91
|
+
int y;
|
92
|
+
int r; // the result goes here
|
93
|
+
r = y ^ ((x ^ y) & -(x < y)); // min(x, y)
|
94
|
+
"""
|
95
|
+
solver = Z3::Solver.new
|
96
|
+
x = Z3.Bitvec("x", 32)
|
97
|
+
y = Z3.Bitvec("y", 32)
|
98
|
+
r = y ^ ((x ^ y) & -c_boolean(solver, x < y, "t"))
|
99
|
+
puts "Validating min without branching"
|
100
|
+
solver.prove!(
|
101
|
+
Z3.Or(
|
102
|
+
Z3.And(x <= y, r == x),
|
103
|
+
Z3.And(y <= y, r == y),
|
104
|
+
)
|
105
|
+
)
|
106
|
+
end
|
107
|
+
|
108
|
+
def validate_max_without_branching!
|
109
|
+
"""
|
110
|
+
int x; // we want to find the minimum of x and y
|
111
|
+
int y;
|
112
|
+
int r; // the result goes here
|
113
|
+
r = x ^ ((x ^ y) & -(x < y)); // max(x, y)
|
114
|
+
"""
|
115
|
+
solver = Z3::Solver.new
|
116
|
+
x = Z3.Bitvec("x", 32)
|
117
|
+
y = Z3.Bitvec("y", 32)
|
118
|
+
r = x ^ ((x ^ y) & -c_boolean(solver, x < y, "t"))
|
119
|
+
puts "Validating max without branching"
|
120
|
+
solver.prove!(
|
121
|
+
Z3.Or(
|
122
|
+
Z3.And(x >= y, r == x),
|
123
|
+
Z3.And(y >= y, r == y),
|
124
|
+
)
|
125
|
+
)
|
126
|
+
end
|
127
|
+
|
128
|
+
def validate_is_power_of_two!
|
129
|
+
"""
|
130
|
+
unsigned int v; // we want to see if v is a power of 2
|
131
|
+
bool f; // the result goes here
|
132
|
+
|
133
|
+
f = (v & (v - 1)) == 0;
|
134
|
+
"""
|
135
|
+
solver = Z3::Solver.new
|
136
|
+
v = Z3.Bitvec("v", 32)
|
137
|
+
f = (v & (v - 1)) == 0
|
138
|
+
|
139
|
+
powers_of_two = (0..31).map{|i| 2**i}
|
140
|
+
naive_is_f_power_of_two = Z3.Or(*powers_of_two.map{|k| v == k})
|
141
|
+
|
142
|
+
puts "Validating is power of two"
|
143
|
+
solver.prove!(
|
144
|
+
Z3.Or(
|
145
|
+
f == naive_is_f_power_of_two,
|
146
|
+
v == 0,
|
147
|
+
)
|
148
|
+
)
|
149
|
+
end
|
150
|
+
|
151
|
+
validate_sign_by_shift!
|
152
|
+
validate_opposite_sign_by_xor!
|
153
|
+
validate_abs_without_branching_1!
|
154
|
+
validate_abs_without_branching_2!
|
155
|
+
validate_min_without_branching!
|
156
|
+
validate_max_without_branching!
|
157
|
+
validate_is_power_of_two!
|
158
|
+
|
159
|
+
"""
|
160
|
+
Based on https://graphics.stanford.edu/~seander/bithacks.html
|
161
|
+
"""
|
data/examples/bridges_solver
CHANGED
@@ -0,0 +1,135 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# NOTE: This is not part of integration test suite as it's fairly slow (30s or so on my machine)
|
4
|
+
|
5
|
+
require_relative "../lib/z3"
|
6
|
+
|
7
|
+
class CLogicPuzzleSolver
|
8
|
+
attr_reader :solver, :wv
|
9
|
+
def initialize
|
10
|
+
@solver = Z3::Solver.new
|
11
|
+
@digits = ["b", "c", "d", "f", "g", "h", "i", "j", "l", "n", "o", "q", "s", "t", "u", "v", "w", "x", "y", "z"]
|
12
|
+
@digit_vars = Hash[@digits.map{|v| [v, digit_var(v)]}]
|
13
|
+
@words = [
|
14
|
+
"bytwycju",
|
15
|
+
"bzuwtwol",
|
16
|
+
"cgyoyfjg",
|
17
|
+
"ctvtwysu",
|
18
|
+
"dhcqxtfw",
|
19
|
+
"diffhlnl",
|
20
|
+
"fjivucti",
|
21
|
+
"htwizvwi",
|
22
|
+
"jqxizzxq",
|
23
|
+
"niiqztgs",
|
24
|
+
"nshtztns",
|
25
|
+
"nttuhlnq",
|
26
|
+
"oigsjgoj",
|
27
|
+
"oncycbxh",
|
28
|
+
"oqbctlzh",
|
29
|
+
"oqcnwbsd",
|
30
|
+
"sfgsoxdd",
|
31
|
+
"sugvqgww",
|
32
|
+
"syhjizjq",
|
33
|
+
"szblgodf",
|
34
|
+
"thhwohwn",
|
35
|
+
"ttligxut",
|
36
|
+
"uclfqvdu",
|
37
|
+
"udluvhcz",
|
38
|
+
"ugdztnwv",
|
39
|
+
"uxztiywn",
|
40
|
+
"vugljtyn",
|
41
|
+
"vyhyjivb",
|
42
|
+
"wwnnnqbw",
|
43
|
+
"xbfziozy",
|
44
|
+
"xsvuojtx",
|
45
|
+
"yjjowdqh",
|
46
|
+
"yzdgotby",
|
47
|
+
"yzvyjjdy",
|
48
|
+
"zoljwdfl",
|
49
|
+
]
|
50
|
+
@wv = Hash[@words.map{|w| [w, word_var(w)]}]
|
51
|
+
end
|
52
|
+
|
53
|
+
def digit_var(name)
|
54
|
+
v = Z3.Bitvec(name, 32)
|
55
|
+
solver.assert v >= 0
|
56
|
+
solver.assert v <= 9
|
57
|
+
v
|
58
|
+
end
|
59
|
+
|
60
|
+
def word_var(name)
|
61
|
+
v = Z3.Bitvec(name, 32)
|
62
|
+
digits = name.chars.map{|c| @digit_vars[c] }
|
63
|
+
val_v = digits.inject(0){|a,b| a*10+b}
|
64
|
+
solver.assert val_v == v
|
65
|
+
v
|
66
|
+
end
|
67
|
+
|
68
|
+
def solve!
|
69
|
+
# Everyone occurs twice, this is not quite that
|
70
|
+
solver.assert Z3.Add(*@digit_vars.values) == 90
|
71
|
+
|
72
|
+
# ^| operator precedence is not like Python's for some reason
|
73
|
+
|
74
|
+
solver.assert wv["bytwycju"] + wv["yzvyjjdy"] ^ wv["vugljtyn"] + wv["ugdztnwv"] | wv["xbfziozy"] == wv["bzuwtwol"]
|
75
|
+
solver.assert wv["wwnnnqbw"] - wv["uclfqvdu"] & wv["oncycbxh"] |(wv["oqcnwbsd"] ^ wv["cgyoyfjg"])== wv["vyhyjivb"]
|
76
|
+
solver.assert wv["yzdgotby"] | wv["oigsjgoj"] | wv["ttligxut"] - wv["dhcqxtfw"] & wv["szblgodf"] == wv["sfgsoxdd"]
|
77
|
+
solver.assert wv["yjjowdqh"] & wv["niiqztgs"] + wv["ctvtwysu"] & wv["diffhlnl"] - wv["thhwohwn"] == wv["xsvuojtx"]
|
78
|
+
solver.assert wv["nttuhlnq"] ^ wv["oqbctlzh"] - wv["nshtztns"] ^ wv["htwizvwi"] + wv["udluvhcz"] == wv["syhjizjq"]
|
79
|
+
|
80
|
+
solver.assert wv["bytwycju"] ^ wv["wwnnnqbw"] & wv["yzdgotby"] + wv["yjjowdqh"] - wv["nttuhlnq"] == wv["fjivucti"]
|
81
|
+
solver.assert wv["yzvyjjdy"] ^ wv["uclfqvdu"] & wv["oigsjgoj"] + wv["niiqztgs"] - wv["oqbctlzh"] == wv["zoljwdfl"]
|
82
|
+
solver.assert wv["vugljtyn"] ^ wv["oncycbxh"] & wv["ttligxut"] + wv["ctvtwysu"] - wv["nshtztns"] == wv["sugvqgww"]
|
83
|
+
solver.assert wv["ugdztnwv"] ^ wv["oqcnwbsd"] & wv["dhcqxtfw"] + wv["diffhlnl"] - wv["htwizvwi"] == wv["uxztiywn"]
|
84
|
+
solver.assert wv["xbfziozy"] ^ wv["cgyoyfjg"] & wv["szblgodf"] + wv["thhwohwn"] - wv["udluvhcz"] == wv["jqxizzxq"]
|
85
|
+
|
86
|
+
key = %W[iw hu fv lu dv cy og lc gy fq od lo fq is ig gu hs hi ds cy oo os iu fs gu lh dq lv gu iw hv gu di hs cy oc iw gc]
|
87
|
+
|
88
|
+
if solver.check == :sat
|
89
|
+
model = solver.model
|
90
|
+
model_vars = {}
|
91
|
+
model.each do |k,v|
|
92
|
+
v = v.to_s.sub(/\A#x/, "").to_i(16)
|
93
|
+
model_vars[k] = v
|
94
|
+
puts "#{k.to_s}=#{v.to_s}"
|
95
|
+
end
|
96
|
+
result = key.map do |ab|
|
97
|
+
a,b = ab.chars
|
98
|
+
av = model_vars[a]
|
99
|
+
bv = model_vars[b]
|
100
|
+
(10*av+bv).chr
|
101
|
+
end
|
102
|
+
puts "Result: #{result.join}"
|
103
|
+
else
|
104
|
+
puts "failed to solve"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
CLogicPuzzleSolver.new.solve!
|
110
|
+
|
111
|
+
# The puzzle:
|
112
|
+
"""
|
113
|
+
We've captured a strange message. It looks like it is encrypted somehow ...
|
114
|
+
iw, hu, fv, lu, dv, cy, og, lc, gy, fq, od, lo, fq, is, ig, gu, hs, hi, ds, cy, oo, os, iu, fs, gu, lh, dq, lv, gu, iw, hv, gu, di, hs, cy, oc, iw, gc
|
115
|
+
|
116
|
+
|
117
|
+
We've also intercepted what seems to be a hint to the key:
|
118
|
+
bytwycju + yzvyjjdy ^ vugljtyn + ugdztnwv | xbfziozy = bzuwtwol
|
119
|
+
^ ^ ^ ^ ^
|
120
|
+
wwnnnqbw - uclfqvdu & oncycbxh | oqcnwbsd ^ cgyoyfjg = vyhyjivb
|
121
|
+
& & & & &
|
122
|
+
yzdgotby | oigsjgoj | ttligxut - dhcqxtfw & szblgodf = sfgsoxdd
|
123
|
+
+ + + + +
|
124
|
+
yjjowdqh & niiqztgs + ctvtwysu & diffhlnl - thhwohwn = xsvuojtx
|
125
|
+
- - - - -
|
126
|
+
nttuhlnq ^ oqbctlzh - nshtztns ^ htwizvwi + udluvhcz = syhjizjq
|
127
|
+
= = = = =
|
128
|
+
fjivucti zoljwdfl sugvqgww uxztiywn jqxizzxq
|
129
|
+
|
130
|
+
Note:
|
131
|
+
assume q != 0
|
132
|
+
a letter is a decimal digit is a letter
|
133
|
+
each digit has exactly two different letter representations
|
134
|
+
C-like operator precedence
|
135
|
+
"""
|