z3 0.0.20181229 → 0.0.20220320

Sign up to get free protection for your applications and to get access to all the features.
Files changed (210) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +0 -0
  3. data/README.md +0 -2
  4. data/Rakefile +8 -1
  5. data/examples/abc_path +187 -0
  6. data/examples/abc_path-1.txt +7 -0
  7. data/examples/algebra_problems +12 -12
  8. data/examples/aquarium +133 -0
  9. data/examples/aquarium-1.txt +11 -0
  10. data/examples/bridges +2 -2
  11. data/examples/bridges-1.txt +0 -0
  12. data/examples/cats_organized_neatly +133 -0
  13. data/examples/cats_organized_neatly-10.txt +15 -0
  14. data/examples/cats_organized_neatly-3.txt +8 -0
  15. data/examples/cats_organized_neatly-48.txt +32 -0
  16. data/examples/circuit_problems +4 -4
  17. data/examples/clogic_puzzle +2 -2
  18. data/examples/color_nonogram +150 -0
  19. data/examples/color_nonogram-1.txt +23 -0
  20. data/examples/crossflip +2 -4
  21. data/examples/dominion +153 -0
  22. data/examples/dominion-1.txt +8 -0
  23. data/examples/dominosa +133 -0
  24. data/examples/dominosa-1.txt +8 -0
  25. data/examples/eulero +99 -0
  26. data/examples/eulero-1.txt +5 -0
  27. data/examples/four_hackers_puzzle +2 -2
  28. data/examples/futoshiki +128 -0
  29. data/examples/futoshiki-1.txt +17 -0
  30. data/examples/kakurasu +73 -0
  31. data/examples/kakurasu-1.txt +2 -0
  32. data/examples/kakuro +2 -2
  33. data/examples/kakuro-1.txt +0 -0
  34. data/examples/killer_sudoku +88 -0
  35. data/examples/killer_sudoku-1.txt +17 -0
  36. data/examples/killer_sudoku-2.txt +53 -0
  37. data/examples/kinematics_problems +20 -20
  38. data/examples/knights_puzzle +2 -2
  39. data/examples/kropki +100 -0
  40. data/examples/kropki-1.txt +13 -0
  41. data/examples/letter_connections +2 -2
  42. data/examples/letter_connections-1.txt +0 -0
  43. data/examples/light_up +2 -2
  44. data/examples/light_up-1.txt +0 -0
  45. data/examples/minisudoku +2 -2
  46. data/examples/minisudoku-1.txt +0 -0
  47. data/examples/miracle_sudoku +135 -0
  48. data/examples/miracle_sudoku-1.txt +9 -0
  49. data/examples/mortal_coil_puzzle +2 -2
  50. data/examples/mortal_coil_puzzle-9.txt +0 -0
  51. data/examples/nanro +245 -0
  52. data/examples/nanro-1.txt +8 -0
  53. data/examples/nine_clocks +106 -0
  54. data/examples/nonogram +2 -2
  55. data/examples/pyramid_nonogram +2 -2
  56. data/examples/regexp_crossword/beginner-1.txt +0 -0
  57. data/examples/regexp_crossword/beginner-2.txt +0 -0
  58. data/examples/regexp_crossword/beginner-3.txt +0 -0
  59. data/examples/regexp_crossword/beginner-4.txt +0 -0
  60. data/examples/regexp_crossword/beginner-5.txt +0 -0
  61. data/examples/regexp_crossword/experienced-1.txt +0 -0
  62. data/examples/regexp_crossword/experienced-2.txt +0 -0
  63. data/examples/regexp_crossword/experienced-3.txt +0 -0
  64. data/examples/regexp_crossword/experienced-4.txt +0 -0
  65. data/examples/regexp_crossword/experienced-5.txt +0 -0
  66. data/examples/regexp_crossword/tutorial-1.txt +0 -0
  67. data/examples/regexp_crossword/tutorial-2.txt +0 -0
  68. data/examples/regexp_crossword/tutorial-3.txt +0 -0
  69. data/examples/regexp_crossword/tutorial-4.txt +0 -0
  70. data/examples/regexp_crossword/tutorial-5.txt +0 -0
  71. data/examples/regexp_crossword/tutorial-6.txt +0 -0
  72. data/examples/regexp_crossword/tutorial-7.txt +0 -0
  73. data/examples/regexp_crossword/tutorial-8.txt +0 -0
  74. data/examples/regexp_crossword/tutorial-9.txt +0 -0
  75. data/examples/regexp_crossword_solver +2 -2
  76. data/examples/regexp_solver +2 -2
  77. data/examples/regexp_string_matcher.rb +0 -0
  78. data/examples/renzoku +124 -0
  79. data/examples/renzoku-1.txt +17 -0
  80. data/examples/sandwich_sudoku +101 -0
  81. data/examples/sandwich_sudoku-1.txt +10 -0
  82. data/examples/selfref +2 -2
  83. data/examples/simple_regexp_parser.rb +0 -0
  84. data/examples/skyscrapers +118 -0
  85. data/examples/skyscrapers-1.txt +6 -0
  86. data/examples/skyscrapers-2.txt +11 -0
  87. data/examples/star_battle +134 -0
  88. data/examples/star_battle-1.txt +10 -0
  89. data/examples/stitches +180 -0
  90. data/examples/stitches-1.txt +11 -0
  91. data/examples/sudoku +2 -2
  92. data/examples/sudoku-1.txt +0 -0
  93. data/examples/suguru +199 -0
  94. data/examples/suguru-1.txt +17 -0
  95. data/examples/verbal_arithmetic +2 -2
  96. data/examples/yajilin +268 -0
  97. data/examples/yajilin-1.txt +10 -0
  98. data/lib/z3/ast.rb +0 -0
  99. data/lib/z3/context.rb +0 -0
  100. data/lib/z3/exception.rb +0 -0
  101. data/lib/z3/expr/arith_expr.rb +0 -0
  102. data/lib/z3/expr/array_expr.rb +0 -0
  103. data/lib/z3/expr/bitvec_expr.rb +47 -2
  104. data/lib/z3/expr/bool_expr.rb +0 -0
  105. data/lib/z3/expr/expr.rb +3 -3
  106. data/lib/z3/expr/float_expr.rb +0 -0
  107. data/lib/z3/expr/int_expr.rb +0 -0
  108. data/lib/z3/expr/real_expr.rb +0 -0
  109. data/lib/z3/expr/rounding_mode_expr.rb +0 -0
  110. data/lib/z3/expr/set_expr.rb +0 -0
  111. data/lib/z3/func_decl.rb +0 -0
  112. data/lib/z3/goal.rb +0 -0
  113. data/lib/z3/hacks.rb +0 -0
  114. data/lib/z3/interface.rb +0 -0
  115. data/lib/z3/low_level.rb +0 -0
  116. data/lib/z3/low_level_auto.rb +138 -10
  117. data/lib/z3/model.rb +0 -0
  118. data/lib/z3/optimize.rb +0 -0
  119. data/lib/z3/printer.rb +0 -0
  120. data/lib/z3/probe.rb +0 -0
  121. data/lib/z3/solver.rb +0 -0
  122. data/lib/z3/sort/array_sort.rb +0 -0
  123. data/lib/z3/sort/bitvec_sort.rb +0 -0
  124. data/lib/z3/sort/bool_sort.rb +0 -0
  125. data/lib/z3/sort/float_sort.rb +0 -0
  126. data/lib/z3/sort/int_sort.rb +0 -0
  127. data/lib/z3/sort/real_sort.rb +0 -0
  128. data/lib/z3/sort/rounding_mode_sort.rb +0 -0
  129. data/lib/z3/sort/set_sort.rb +0 -0
  130. data/lib/z3/sort/sort.rb +0 -0
  131. data/lib/z3/tactic.rb +0 -0
  132. data/lib/z3/very_low_level.rb +5 -1
  133. data/lib/z3/very_low_level_auto.rb +35 -3
  134. data/lib/z3.rb +0 -0
  135. data/spec/array_expr_spec.rb +0 -0
  136. data/spec/array_sort_spec.rb +0 -0
  137. data/spec/bitvec_expr_spec.rb +13 -0
  138. data/spec/bitvec_sort_spec.rb +0 -0
  139. data/spec/bool_expr_spec.rb +0 -0
  140. data/spec/bool_sort_spec.rb +0 -0
  141. data/spec/coverage_helper.rb +0 -0
  142. data/spec/expr_spec.rb +0 -0
  143. data/spec/float_expr_spec.rb +0 -0
  144. data/spec/float_sort_spec.rb +0 -0
  145. data/spec/goal_spec.rb +0 -0
  146. data/spec/int_expr_spec.rb +0 -0
  147. data/spec/int_sort_spec.rb +0 -0
  148. data/spec/integration/abc_path_spec.rb +21 -0
  149. data/spec/integration/algebra_problems_spec.rb +0 -0
  150. data/spec/integration/aquarium_spec.rb +27 -0
  151. data/spec/integration/basic_int_math_spec.rb +0 -0
  152. data/spec/integration/basic_logic_spec.rb +0 -0
  153. data/spec/integration/bit_tricks_spec.rb +0 -0
  154. data/spec/integration/bridges_spec.rb +0 -0
  155. data/spec/integration/cats_organized_neatly_spec.rb +14 -0
  156. data/spec/integration/cicruit_problem_spec.rb +0 -0
  157. data/spec/integration/color_nonogram_spec.rb +28 -0
  158. data/spec/integration/crossflip_spec.rb +0 -0
  159. data/spec/integration/dominion_spec.rb +14 -0
  160. data/spec/integration/dominosa_spec.rb +21 -0
  161. data/spec/integration/eulero_spec.rb +11 -0
  162. data/spec/integration/four_hackers_puzzle_spec.rb +0 -0
  163. data/spec/integration/futoshiki_spec.rb +23 -0
  164. data/spec/integration/geometry_problem_spec.rb +0 -0
  165. data/spec/integration/kakurasu_spec.rb +18 -0
  166. data/spec/integration/kakuro_spec.rb +0 -0
  167. data/spec/integration/killer_sudoku_spec.rb +10 -0
  168. data/spec/integration/kinematics_problems_spec.rb +0 -0
  169. data/spec/integration/knights_puzzle_spec.rb +11 -11
  170. data/spec/integration/kropki_spec.rb +19 -0
  171. data/spec/integration/letter_connections_spec.rb +0 -0
  172. data/spec/integration/light_up_spec.rb +0 -0
  173. data/spec/integration/minisudoku_spec.rb +0 -0
  174. data/spec/integration/miracle_sudoku_spec.rb +15 -0
  175. data/spec/integration/mortal_coil_puzzle_spec.rb +8 -6
  176. data/spec/integration/nanro_spec.rb +39 -0
  177. data/spec/integration/nine_clocks_spec.rb +30 -0
  178. data/spec/integration/nonogram_spec.rb +0 -0
  179. data/spec/integration/oneofus_spec.rb +0 -0
  180. data/spec/integration/pyramid_nonogram_spec.rb +0 -0
  181. data/spec/integration/regexp_crossword_solver_spec.rb +1 -1
  182. data/spec/integration/regexp_solver_spec.rb +0 -0
  183. data/spec/integration/renzoku_spec.rb +23 -0
  184. data/spec/integration/sandwich_sudoku_spec.rb +15 -0
  185. data/spec/integration/selfref_spec.rb +0 -0
  186. data/spec/integration/skyscraper_spec.rb +10 -0
  187. data/spec/integration/star_battle_spec.rb +27 -0
  188. data/spec/integration/stitches_spec.rb +25 -0
  189. data/spec/integration/sudoku_spec.rb +0 -0
  190. data/spec/integration/suguru_spec.rb +23 -0
  191. data/spec/integration/verbal_arithmetic_spec.rb +0 -0
  192. data/spec/integration/yajilin_spec.rb +25 -0
  193. data/spec/integration/zebra_puzzle_spec.rb +0 -0
  194. data/spec/interface_spec.rb +0 -0
  195. data/spec/model_spec.rb +0 -0
  196. data/spec/optimize_spec.rb +3 -1
  197. data/spec/printer_spec.rb +0 -0
  198. data/spec/probe_spec.rb +0 -0
  199. data/spec/real_expr_spec.rb +0 -0
  200. data/spec/real_sort_spec.rb +0 -0
  201. data/spec/rounding_mode_expr_spec.rb +0 -0
  202. data/spec/rounding_mode_sort_spec.rb +0 -0
  203. data/spec/set_expr_spec.rb +15 -9
  204. data/spec/set_sort_spec.rb +0 -0
  205. data/spec/solver_spec.rb +1 -2
  206. data/spec/sort_spec.rb +0 -0
  207. data/spec/spec_helper.rb +15 -0
  208. data/spec/tactic_spec.rb +0 -0
  209. data/spec/z3_spec.rb +0 -0
  210. metadata +85 -5
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "pathname"
4
+ require_relative "../lib/z3"
5
+
6
+ class MiracleSudokuSolver
7
+ def initialize(path)
8
+ data = Pathname(path).read
9
+ data = data.strip.split("\n").map do |line|
10
+ line.split.map{|c| c == "." ? nil : c.to_i}
11
+ end
12
+ @data = data
13
+ raise "Bad size" unless @data.size == 9
14
+ raise "Bad size" unless @data.all?{|row| row.size == 9}
15
+ @solver = Z3::Solver.new
16
+ end
17
+
18
+ def king_moves
19
+ [
20
+ [-1,-1],
21
+ [-1, 0],
22
+ [-1,+1],
23
+ [ 0,-1],
24
+ [ 0,+1],
25
+ [+1,-1],
26
+ [+1, 0],
27
+ [+1,+1],
28
+ ]
29
+ end
30
+
31
+ def knight_moves
32
+ [
33
+ [-2, -1],
34
+ [-2, +1],
35
+ [-1, -2],
36
+ [-1, +2],
37
+ [+1, -2],
38
+ [+1, +2],
39
+ [+2, -1],
40
+ [+2, +1],
41
+ ]
42
+ end
43
+
44
+ def orthogonal_moves
45
+ [
46
+ [-1, 0],
47
+ [+1, 0],
48
+ [ 0, -1],
49
+ [ 0, +1],
50
+ ]
51
+ end
52
+
53
+ def call
54
+ @cells = (0..8).map do |y|
55
+ (0..8).map do |x|
56
+ cell_var(data_at(x,y), x, y)
57
+ end
58
+ end
59
+
60
+ @cells.each do |row|
61
+ @solver.assert Z3.Distinct(*row)
62
+ end
63
+ @cells.transpose.each do |column|
64
+ @solver.assert Z3.Distinct(*column)
65
+ end
66
+ @cells.each_slice(3) do |rows|
67
+ rows.transpose.each_slice(3) do |square|
68
+ @solver.assert Z3.Distinct(*square.flatten)
69
+ end
70
+ end
71
+
72
+ each_coord do |x,y|
73
+ [*king_moves, *knight_moves].each do |dx, dy|
74
+ x2 = x + dx
75
+ y2 = y + dy
76
+ next unless in_bounds?(x2, y2)
77
+ @solver.assert var_at(x,y) != var_at(x2,y2)
78
+ end
79
+
80
+ orthogonal_moves.each do |dx, dy|
81
+ x2 = x + dx
82
+ y2 = y + dy
83
+ next unless in_bounds?(x2, y2)
84
+ @solver.assert var_at(x,y) != var_at(x2,y2) + 1
85
+ @solver.assert var_at(x,y) != var_at(x2,y2) - 1
86
+ end
87
+ end
88
+
89
+ if @solver.satisfiable?
90
+ @model = @solver.model
91
+ print_answer!
92
+ else
93
+ puts "failed to solve"
94
+ end
95
+ end
96
+
97
+ def each_coord
98
+ 9.times do |x|
99
+ 9.times do |y|
100
+ yield(x, y)
101
+ end
102
+ end
103
+ end
104
+
105
+ def in_bounds?(x,y)
106
+ (0..8).include?(x) and (0..8).include?(y)
107
+ end
108
+
109
+ def var_at(x, y)
110
+ return nil unless in_bounds?(x,y)
111
+ @cells[y][x]
112
+ end
113
+
114
+ def data_at(x, y)
115
+ return nil unless in_bounds?(x,y)
116
+ @data[y][x]
117
+ end
118
+
119
+ def cell_var(cell, x, y)
120
+ v = Z3.Int("cell[#{x+1},#{y+1}]")
121
+ @solver.assert v >= 1
122
+ @solver.assert v <= 9
123
+ @solver.assert v == cell if cell != nil
124
+ v
125
+ end
126
+
127
+ def print_answer!
128
+ @cells.each do |row|
129
+ puts row.map{|v| @model[v]}.join(" ")
130
+ end
131
+ end
132
+ end
133
+
134
+ path = ARGV[0] || Pathname(__dir__) + "miracle_sudoku-1.txt"
135
+ MiracleSudokuSolver.new(path).call
@@ -0,0 +1,9 @@
1
+ . . . . . . . . .
2
+ . . . . . . . . .
3
+ . . . . . . . . .
4
+ . . . . . . . . .
5
+ . . 1 . . . . . .
6
+ . . . . . . 2 . .
7
+ . . . . . . . . .
8
+ . . . . . . . . .
9
+ . . . . . . . . .
@@ -78,7 +78,7 @@ class MortalCoilSolver
78
78
  end
79
79
  end
80
80
 
81
- def solve!
81
+ def call
82
82
  setup_vars!
83
83
  line_continuity!
84
84
  line_goes_until_it_hits_something!
@@ -102,4 +102,4 @@ class MortalCoilSolver
102
102
  end
103
103
 
104
104
  path = ARGV[0] || Pathname(__dir__) + "mortal_coil_puzzle-9.txt"
105
- MortalCoilSolver.new(path).solve!
105
+ MortalCoilSolver.new(path).call
File without changes
data/examples/nanro ADDED
@@ -0,0 +1,245 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/z3"
4
+ require "pathname"
5
+
6
+ # https://www.gmpuzzles.com/blog/nanro-rules-and-info/
7
+
8
+ class Nanro
9
+ def initialize(path)
10
+ data = Pathname(path)
11
+ .readlines
12
+ .map{|row| row.chomp.split}
13
+ @ysize = data.size
14
+ @xsize = data[0].size
15
+ raise unless data.all?{|row| row.size == @ysize}
16
+ @regions = data
17
+ .map{|row|
18
+ row.map{|cell|
19
+ cell.gsub(/\d|\./, "")
20
+ }
21
+ }
22
+ @hints = data
23
+ .map{|row|
24
+ row.map{|cell|
25
+ cell[1] =~ /(\d+)/ ? $1.to_i : nil
26
+ }
27
+ }
28
+ @solver = Z3::Solver.new
29
+ end
30
+
31
+ def assert_each_cell_is_0_or_rvar
32
+ each_xy do |x,y|
33
+ @solver.assert Z3.Or(
34
+ cvar(x,y) == 0,
35
+ cvar(x,y) == rvar(region_at(x,y))
36
+ )
37
+ end
38
+ end
39
+
40
+ def assert_rvar_equals_number_of_numbered_cells_in_region
41
+ cells_by_region.each do |r, xys|
42
+ nonzeroes = xys.map{|x,y| (cvar(x,y) == 0).ite(0,1)}
43
+ @solver.assert rvar(r) == Z3.Add(*nonzeroes)
44
+ @solver.assert rvar(r) >= 1
45
+ end
46
+ end
47
+
48
+ def assert_hints_obeyed
49
+ each_xy do |x,y|
50
+ if hint_at(x,y)
51
+ @solver.assert cvar(x,y) == hint_at(x,y)
52
+ end
53
+ end
54
+ end
55
+
56
+ def assert_no_numbered_squares
57
+ each_xy do |x,y|
58
+ next unless on_board?(x+1,y+1)
59
+ @solver.assert Z3.Or(
60
+ cvar(x,y) == 0,
61
+ cvar(x+1,y) == 0,
62
+ cvar(x,y+1) == 0,
63
+ cvar(x+1,y+1) == 0,
64
+ )
65
+ end
66
+ end
67
+
68
+ def assert_no_same_number_between_regions
69
+ each_xy do |x,y|
70
+ neighbours(x,y).each do |nx,ny|
71
+ next if region_at(x,y) == region_at(nx,ny)
72
+ @solver.assert (cvar(x,y) != 0).implies(cvar(x,y) != cvar(nx,ny))
73
+ end
74
+ end
75
+ end
76
+
77
+ def assert_numbered_cells_all_connected
78
+ max_value = @xsize * @ysize + 10
79
+
80
+ each_xy do |x,y|
81
+ @solver.assert nvar(x,y) >= 0
82
+ @solver.assert (cvar(x,y) == 0).implies(nvar(x,y) == max_value)
83
+ @solver.assert (cvar(x,y) != 0).implies(nvar(x,y) < max_value)
84
+
85
+ nval = neighbours(x,y)
86
+ .map{|nx,ny|
87
+ (cvar(nx,ny) == 0).ite(max_value, nvar(nx,ny) + 1)
88
+ }
89
+ .reduce{|a,b| (a <= b).ite(a, b) }
90
+
91
+ @solver.assert (cvar(x,y) != 0).implies(Z3.Or(nvar(x,y) == 0, nvar(x,y) == nval))
92
+ end
93
+
94
+ @solver.assert Z3.Add(
95
+ *enum_for(:each_xy).map{|x,y|
96
+ (nvar(x,y) == 0).ite(1,0)
97
+ }) == 1
98
+ end
99
+
100
+ def call
101
+ assert_hints_obeyed
102
+ assert_no_numbered_squares
103
+ assert_each_cell_is_0_or_rvar
104
+ assert_rvar_equals_number_of_numbered_cells_in_region
105
+ assert_no_same_number_between_regions
106
+ assert_numbered_cells_all_connected
107
+
108
+ if @solver.satisfiable?
109
+ @model = @solver.model
110
+ print_answer!
111
+ else
112
+ puts "failed to solve"
113
+ end
114
+ end
115
+
116
+ private
117
+
118
+ def neighbours(x,y)
119
+ [
120
+ [x+1,y],
121
+ [x-1,y],
122
+ [x,y+1],
123
+ [x,y-1],
124
+ ].select{|nx,ny| on_board?(nx,ny)}
125
+ end
126
+
127
+ def cells_by_region
128
+ @cells_by_region ||= enum_for(:each_xy).group_by{|x,y| region_at(x,y)}
129
+ end
130
+
131
+ def rvar(r)
132
+ Z3.Int("r[#{r}]")
133
+ end
134
+
135
+ def cvar(x,y)
136
+ Z3.Int("c[#{x},#{y}]")
137
+ end
138
+
139
+ def nvar(x,y)
140
+ Z3.Int("n[#{x},#{y}]")
141
+ end
142
+
143
+ def each_xy
144
+ @ysize.times do |y|
145
+ @xsize.times do |x|
146
+ yield(x,y)
147
+ end
148
+ end
149
+ end
150
+
151
+ def on_board?(x,y)
152
+ x >= 0 and y >= 0 and x < @xsize and y < @ysize
153
+ end
154
+
155
+ def region_at(x,y)
156
+ return nil unless on_board?(x,y)
157
+ @regions[y][x]
158
+ end
159
+
160
+ def hint_at(x,y)
161
+ return nil unless on_board?(x,y)
162
+ @hints[y][x]
163
+ end
164
+
165
+ def print_corner?(x, y)
166
+ [
167
+ region_at(x,y),
168
+ region_at(x-1,y),
169
+ region_at(x,y-1),
170
+ region_at(x-1,y-1),
171
+ ].uniq.size > 1
172
+ end
173
+
174
+ def print_edge?(x1, y1, x2, y2)
175
+ region_at(x1,y1) != region_at(x2,y2)
176
+ end
177
+
178
+ def corner_output(x,y)
179
+ if print_corner?(x, y)
180
+ "*"
181
+ else
182
+ " "
183
+ end
184
+ end
185
+
186
+ def vedge_output(x,y)
187
+ if print_edge?(x, y, x, y-1)
188
+ "---"
189
+ else
190
+ " "
191
+ end
192
+ end
193
+
194
+ def hedge_output(x,y)
195
+ if print_edge?(x, y, x-1, y)
196
+ "|"
197
+ else
198
+ " "
199
+ end
200
+ end
201
+
202
+ def print_answer!
203
+ (0..@ysize).each do |y|
204
+ (0..@xsize).each do |x|
205
+ print corner_output(x,y)
206
+ next if x == @xsize
207
+ print vedge_output(x,y)
208
+ end
209
+ print "\n"
210
+
211
+ next if y == @ysize
212
+
213
+ (0..@xsize).each do |x|
214
+ print hedge_output(x,y)
215
+ next if x == @xsize
216
+ print " "
217
+ end
218
+ print "\n"
219
+
220
+ (0..@xsize).each do |x|
221
+ print hedge_output(x,y)
222
+ next if x == @xsize
223
+ print " "
224
+ c = @model[cvar(x,y)].to_i
225
+ if c == 0
226
+ print " "
227
+ else
228
+ print c
229
+ end
230
+ print " "
231
+ end
232
+ print "\n"
233
+
234
+ (0..@xsize).each do |x|
235
+ print hedge_output(x,y)
236
+ next if x == @xsize
237
+ print " "
238
+ end
239
+ print "\n"
240
+ end
241
+ end
242
+ end
243
+
244
+ path = ARGV[0] || Pathname(__dir__) + "nanro-1.txt"
245
+ Nanro.new(path).call
@@ -0,0 +1,8 @@
1
+ a6 a. a. a. a. e. f. f3
2
+ a. c. a. a. d. e. f. f.
3
+ b. c. t. t. w. e. u. f.
4
+ g. r. s. x. w. v. u. f.
5
+ g. r. x. x. w. u. u3 p.
6
+ g. q. x. l. m. o. o. p.
7
+ g. i. j. l. o. o3 o. p.
8
+ h. i. j. k. n2 n. n. p.
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env ruby
2
+ # From Tested on Humans Escape Room game
3
+
4
+ require_relative "../lib/z3"
5
+
6
+ class NineClocks
7
+ def initialize
8
+ @solver = Z3::Solver.new
9
+
10
+ @inputs = {}
11
+ @outputs = {}
12
+
13
+ # Setup
14
+ each_xy do |x,y|
15
+ @inputs[[x,y]] = Z3.Bitvec("i#{x},#{y}", 2)
16
+ @outputs[[x,y]] = Z3.Bitvec("o#{x},#{y}", 2)
17
+ end
18
+
19
+ # Rules
20
+ neighbours = {}
21
+ each_xy do |x,y|
22
+ out = @outputs[[x,y]]
23
+ neighbours[out] = []
24
+ each_xy do |xx, yy|
25
+ if (xx-x).abs + (yy-y).abs <= 1
26
+ neighbours[out] << @inputs[[xx,yy]]
27
+ end
28
+ end
29
+
30
+ neighbours.each do |ovar, ivars|
31
+ @solver.assert ovar == Z3.Add(*ivars)
32
+ end
33
+ end
34
+ end
35
+
36
+ def each_xy
37
+ 3.times do |x|
38
+ 3.times do |y|
39
+ yield(x,y)
40
+ end
41
+ end
42
+ end
43
+
44
+ def target_corner
45
+ each_xy do |x,y|
46
+ if x == 0 and y == 0
47
+ @solver.assert @outputs[[x,y]] == 1
48
+ else
49
+ @solver.assert @outputs[[x,y]] == 0
50
+ end
51
+ end
52
+ self
53
+ end
54
+
55
+ def target_edge
56
+ each_xy do |x,y|
57
+ if x == 0 and y == 1
58
+ @solver.assert @outputs[[x,y]] == 1
59
+ else
60
+ @solver.assert @outputs[[x,y]] == 0
61
+ end
62
+ end
63
+ self
64
+ end
65
+
66
+ def target_center
67
+ each_xy do |x,y|
68
+ if x == 1 and y == 1
69
+ @solver.assert @outputs[[x,y]] == 1
70
+ else
71
+ @solver.assert @outputs[[x,y]] == 0
72
+ end
73
+ end
74
+ self
75
+ end
76
+
77
+ def solve
78
+ if @solver.satisfiable?
79
+ model = @solver.model
80
+
81
+ puts "IN:"
82
+ 3.times do |x|
83
+ 3.times do |y|
84
+ ivar = model[@inputs[[x,y]]]
85
+ print ivar, " "
86
+ end
87
+ print "\n"
88
+ end
89
+
90
+ puts "OUT:"
91
+ 3.times do |x|
92
+ 3.times do |y|
93
+ ivar = model[@outputs[[x,y]]]
94
+ print ivar, " "
95
+ end
96
+ print "\n"
97
+ end
98
+ else
99
+ puts "Not satisfiable"
100
+ end
101
+ end
102
+ end
103
+
104
+ NineClocks.new.target_corner.solve
105
+ NineClocks.new.target_edge.solve
106
+ NineClocks.new.target_center.solve
data/examples/nonogram CHANGED
@@ -76,7 +76,7 @@ class Nonogram
76
76
  end
77
77
  end
78
78
 
79
- def solve!
79
+ def call
80
80
  @cells = (0...@ysize).map{|y|
81
81
  (0...@xsize).map{|x|
82
82
  Z3.Bool("cell[#{x+1},#{y+1}]")
@@ -149,4 +149,4 @@ nonogram = Nonogram.new(
149
149
  ]
150
150
  )
151
151
 
152
- nonogram.solve!
152
+ nonogram.call
@@ -27,7 +27,7 @@ class PyramidNonogram
27
27
  end
28
28
  end
29
29
 
30
- def solve!
30
+ def call
31
31
  if @solver.satisfiable?
32
32
  @model = @solver.model
33
33
  print_answer!
@@ -163,4 +163,4 @@ pyramid_nonogram.left_to_bottom(
163
163
  [_],
164
164
  [_],
165
165
  )
166
- pyramid_nonogram.solve!
166
+ pyramid_nonogram.call
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -43,7 +43,7 @@ class RegexpCrosswordSolver
43
43
  SimpleRegexpParser.new(@rows[y], "row-#{y}").parse
44
44
  end
45
45
 
46
- def solve!
46
+ def call
47
47
  @crossword = {}
48
48
  @xsize.times do |x|
49
49
  @ysize.times do |y|
@@ -77,4 +77,4 @@ class RegexpCrosswordSolver
77
77
  end
78
78
 
79
79
  path = ARGV[0] || Pathname(__dir__) + "regexp_crossword/tutorial-1.txt"
80
- RegexpCrosswordSolver.new(path).solve!
80
+ RegexpCrosswordSolver.new(path).call
@@ -11,7 +11,7 @@ class RegexpSolver
11
11
  @solver = Z3::Solver.new
12
12
  end
13
13
 
14
- def solve!
14
+ def call
15
15
  @str = (0...@length).map do |i|
16
16
  v = Z3.Int("char[#{i}]")
17
17
  @solver.assert v >= 0
@@ -40,4 +40,4 @@ end
40
40
 
41
41
  length = ARGV[0].to_i
42
42
  regexp = ARGV[1]
43
- RegexpSolver.new(length, regexp).solve!
43
+ RegexpSolver.new(length, regexp).call
File without changes