I had a book gifted that really fits right in my wheelhouse. The book The Turing Tests - Expert Numbers puzzles, has a large collection of puzzles ripe for solving.
![]() |
Domino placement puzzle |
0-0 0-1 0-2 0-3 0-4 0-5 0-6 1-1 1-2 1-3 1-4 1-5 1-6 2-2 2-3 2-4 2-5 2-6 3-3 3-4 3-5 3-6 4-4 4-5 4-6 5-5 5-6 6-6
A suitable text encoding of the puzzle looks like:
#dp 0-6 dp_001.txt TTT P7
xxxx66
xxx0421
xxx6356
x00116541
0326105431
0215252430
x22130544
xxx6346
xxx4353
xxxx25
-
6-4,73-83
The encoding of the clue hints at how the problem is broken down for solving. A square numbered grid (0 to 99 in 10 lines) is used to represent the placement board with each tile covering two adjacent cells. Each tile end has a non-unique number but each tile pair is unique and the ends must be in adjacent cells. To solve the puzzle a grid square number must be found for each end of all the tiles. The tactic is to solve for each end of each tile as a separate value but limited to the places it's allowed in the layout grid.
The logic of the puzzle falls out as :
- Each domino tile is an adjacent pair of non-unique numbers in the range 0-6,
- All tiles must be placed once and once only,
- No tile can overlap another or have a gaps in the final arrangement, but not all squares of the 10*10 grid are used.
- A clue piece is provided.
- Declaration of 56 integer variables, one for the position of each end of all the tiles,
- Setting of the 2 clue results,
- Making sure that each tile end sits on it's own square,
- Limit each tile end (variable) to only those squares on the provided layout diagram that match. The 0s can only go on a 0 square, 1s on 1 etc.
- Make sure that both ends of a tile sit on adjacent squares.
- Set the solver into integer mode and
- Retrieve the results.
5. Set the Solver into integer mode and make it generate values
1 (set-logic LIA)
2 (set-option :produce-models true)
3 (set-option :produce-assignments true)
1. Declare the variable to hold the board square values as answers. The [0-0] tile is the two variable V00_00 and V00_10, the [5-6] tile is V50-06 and V50_16.
4 (declare-const V00_00 Int)
5 (declare-const V00_10 Int)
6 (declare-const V00_01 Int)
7 (declare-const V00_11 Int)
8 (declare-const V00_02 Int)
9 (declare-const V00_12 Int)
10 (declare-const V00_03 Int)
11 (declare-const V00_13 Int)
12 (declare-const V00_04 Int)
......snip
55 (declare-const V50_15 Int)
56 (declare-const V50_06 Int)
57 (declare-const V50_16 Int)
58 (declare-const V60_06 Int)
59 (declare-const V60_16 Int)
2. Set to two known clue values
60 (assert (= V40_06 83 ))
61 (assert (= V40_16 73 ))
3. Each variable representing the value of one tile end must have a unique answer, being the grid square it will sit on.
62 (assert (distinct V00_00 V00_10 V00_01 V00_11 V00_02 V00_12 V00_03 V00_13 V00_04 V00_14 V00_05 V00_15 V00_06 V00_16 V10_01 V10_11 V10_02 V10_12 V10_03 V10_13 V10_04 V10_14 V10_05 V10_15 V10_06 V10_16 V20_02 V20_12 V20_03 V20_13 V20_04 V20_14 V20_05 V20_15 V20_06 V20_16 V30_03 V30_13 V30_04 V30_14 V30_05 V30_15 V30_06 V30_16 V40_04 V40_14 V40_05 V40_15 V40_06 V40_16 V50_05 V50_15 V50_06 V50_16 V60_06 V60_16 ))
4. Each variable must only have the answer that match its face value number. In the layout grid the 0 appears in 7 squares 13, 31, 32, 40, 45, 50, 59, 65. Therefore we must force each of the variables that has a face number 0 to be one of these grid square values.
63 (assert (or (= V00_00 13) (= V00_00 31) (= V00_00 32) (= V00_00 40) (= V00_00 45) (= V00_00 50) (= V00_00 59) (= V00_00 65) ))
64 (assert (or (= V00_01 13) (= V00_01 31) (= V00_01 32) (= V00_01 40) (= V00_01 45) (= V00_01 50) (= V00_01 59) (= V00_01 65) ))
65 (assert (or (= V00_02 13) (= V00_02 31) (= V00_02 32) (= V00_02 40) (= V00_02 45) (= V00_02 50) (= V00_02 59) (= V00_02 65) ))
66 (assert (or (= V00_03 13) (= V00_03 31) (= V00_03 32) (= V00_03 40) (= V00_03 45) (= V00_03 50) (= V00_03 59) (= V00_03 65) ))
67 (assert (or (= V00_04 13) (= V00_04 31) (= V00_04 32) (= V00_04 40) (= V00_04 45) (= V00_04 50) (= V00_04 59) (= V00_04 65) ))
68 (assert (or (= V00_05 13) (= V00_05 31) (= V00_05 32) (= V00_05 40) (= V00_05 45) (= V00_05 50) (= V00_05 59) (= V00_05 65) ))
...snip
116 (assert (or (= V50_16 4) (= V50_16 5) (= V50_16 23) (= V50_16 26) (= V50_16 35) (= V50_16 43) (= V50_16 73) (= V50_16 76) ))
117 (assert (or (= V60_06 4) (= V60_06 5) (= V60_06 23) (= V60_06 26) (= V60_06 35) (= V60_06 43) (= V60_06 73) (= V60_06 76) ))
118 (assert (or (= V60_16 4) (= V60_16 5) (= V60_16 23) (= V60_16 26) (= V60_16 35) (= V60_16 43) (= V60_16 73) (= V60_16 76) ))
5. Both of the tile ends must be within 1 square of each other end. The values in the variables V10_06 V10_16 represents each end of the [0-6] tile and must be only one grid square away from each other. East-west separation is 1 grid square North-South is 10 grid squares.
119 (assert ( or (= 1 (- V00_00 V00_10)) (= 1 (- V00_10 V00_00)) (= 10 (- V00_00 V00_10)) (= 10 (- V00_10 V00_00)) )) ; pair 0 0 ~ V00_00 V00_10
120 (assert ( or (= 1 (- V00_01 V00_11)) (= 1 (- V00_11 V00_01)) (= 10 (- V00_01 V00_11)) (= 10 (- V00_11 V00_01)) )) ; pair 0 1 ~ V00_01 V00_11
121 (assert ( or (= 1 (- V00_02 V00_12)) (= 1 (- V00_12 V00_02)) (= 10 (- V00_02 V00_12)) (= 10 (- V00_12 V00_02)) )) ; pair 0 2 ~ V00_02 V00_12
122 (assert ( or (= 1 (- V00_03 V00_13)) (= 1 (- V00_13 V00_03)) (= 10 (- V00_03 V00_13)) (= 10 (- V00_13 V00_03)) )) ; pair 0 3 ~ V00_03 V00_13
123 (assert ( or (= 1 (- V00_04 V00_14)) (= 1 (- V00_14 V00_04)) (= 10 (- V00_04 V00_14)) (= 10 (- V00_14 V00_04)) )) ; pair 0 4 ~ V00_04 V00_14
124 (assert ( or (= 1 (- V00_05 V00_15)) (= 1 (- V00_15 V00_05)) (= 10 (- V00_05 V00_15)) (= 10 (- V00_15 V00_05)) )) ; pair 0 5 ~ V00_05 V00_15
.... snip
143 (assert ( or (= 1 (- V40_06 V40_16)) (= 1 (- V40_16 V40_06)) (= 10 (- V40_06 V40_16)) (= 10 (- V40_16 V40_06)) )) ; pair 4 6 ~ V40_06 V40_16
144 (assert ( or (= 1 (- V50_05 V50_15)) (= 1 (- V50_15 V50_05)) (= 10 (- V50_05 V50_15)) (= 10 (- V50_15 V50_05)) )) ; pair 5 5 ~ V50_05 V50_15
145 (assert ( or (= 1 (- V50_06 V50_16)) (= 1 (- V50_16 V50_06)) (= 10 (- V50_06 V50_16)) (= 10 (- V50_16 V50_06)) )) ; pair 5 6 ~ V50_06 V50_16
146 (assert ( or (= 1 (- V60_06 V60_16)) (= 1 (- V60_16 V60_06)) (= 10 (- V60_06 V60_16)) (= 10 (- V60_16 V60_06)) )) ; pair 6 6 ~ V60_06 V60_16
7. Complete the logic lines and request the results
147 (check-sat)
148 (get-value ( V00_00 V00_10 V00_01 V00_11 V00_02 V00_12 V00_03 V00_13 V00_04 V00_14 V00_05 V00_15 V00_06 V00_16 V10_01 V10_11 V10_02 V10_12 V10_03 V10_13 V10_04 V10_14 V10_05 V10_15 V10_06 V10_16 V20_02 V20_12 V20_03 V20_13 V20_04 V20_14 V20_05 V20_15 V20_06 V20_16 V30_03 V30_13 V30_04 V30_14 V30_05 V30_15 V30_06 V30_16 V40_04 V40_14 V40_05 V40_15 V40_06 V40_16 V50_05 V50_15 V50_06 V50_16 V60_06 V60_16 ))
149 (exit)
sat
( (V00_00 31)
(V00_10 32)
(V00_01 59)
(V00_11 49)
(V00_02 50)
...... snip
(V50_15 85)
(V50_06 36)
(V50_16 26)
(V60_06 4)
(V60_16 5) )
Final Comments
% time ./domPlace_smt.pl < dp_001.txt | ../../solver_mathsat5 | ./domPlace_smt.pl -f dp_001.txt > z.html
./domPlace_smt.pl < dp_001.txt 0.01s user 0.00s system 87% cpu 0.012 total
../../solver_mathsat5 0.31s user 0.02s system 98% cpu 0.334 total
././domPlace_smt.pl -f dp_001.txt > z.html 0.01s user 0.00s system 3% cpu 0.334 total
The approach of solving for each end of a tile was seen as less complex than trying to solve of placement and orientation of each domino as a whole. Adding the extra constraint that the two ends of the tile must be next to each other and using creative variable naming completed the excersize.
Both the Mathsat5 and Z3 solvers were able to complete this test using the SMT language as input.
No comments:
Post a Comment