-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmagichex.4th
More file actions
262 lines (221 loc) · 6.79 KB
/
magichex.4th
File metadata and controls
262 lines (221 loc) · 6.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
\ constraint satisfaction problem semi-general stuff
\ failure on a branch of the search tree is indicated by an exception
"no (more) solutions" exception constant failure
\ value trail stack (records original value of changed cells)
[undefined] trail-elements [if] 10000 constant trail-elements [then]
trail-elements 2* cells allocate throw constant trail-stack
variable tsp trail-stack trail-elements 2* cells + tsp !
: !bt ( x addr -- )
\ like !, but records the old value on the trail stack
dup @ over ( x addr old-x addr )
tsp @ 2 cells - dup tsp ! 2! ( x addr )
! ;
: undo ( addr -- )
\ undo everything on the trail stack above addr, starting from the top
dup tsp @ u+do
i 2@ !
2 cells +loop
tsp ! ;
\ linked list of constraints
0
field: list-next
field: list-constraint \ xt of constraint
constant list-size
: instconstraints {: u var list -- :}
\ perform all constraints after setting var to u
list begin {: l :}
l while
u var l list-constraint @ execute
l list-next @
repeat ;
: insert-constraint {: xt listp -- :}
\ insert xt at in the list pointed to by listp
list-size allocate throw {: l :}
listp @ l list-next !
xt l list-constraint !
l listp ! ;
: .constraints {: list -- :}
list begin {: l :}
l while
l .addr.
l list-next @
repeat ;
\ variable in a constraint satisfaction problem
0
field: var-val \ value 0-63 if instantiated, negative if not
field: var-bits \ potential values
field: var-wheninst \ linked list of constraints woken up when instantiated
constant var-size
: .v {: v -- :} \ for debugging
cr v .id ." : "
." val=" v var-val @ .
." bits=" v var-bits @ hex.
." wheninst:" v var-wheninst @ .constraints ;
: domain {: u1 u2 -- :}
\ generate a constraint variable name ( -- var )
\ with potential values [u1,u2]
create here {: var :} var-size allot
-1 var var-val !
1 u2 1+ lshift 1- 1 u1 lshift 1- xor var var-bits !
0 var var-wheninst ! ;
: !var {: u var -- :}
\ instantiate var to u; throws iff var cannot be instantiated to u
\ (not in the remaining values, or a constraint is not
\ satisfiable)
u 64 u>= if failure throw then
var var-val @ dup 0>= swap u <> and if failure throw then
var var-bits @ 1 u lshift and 0= if failure throw then
u var var-val !bt
u var var var-wheninst @ instconstraints ;
: constraint! ( xt var -- )
var-wheninst insert-constraint ;
\ labeling support
: label {: var xt -- :}
\ try out the first possible value for var; on CATCHing FAILURE,
\ try the next, and so on; when no value is left, throw FAILURE.
var var-val @ 0< if
var var-bits @ 64 0 do ( x )
dup 1 and if ( x )
tsp @ xt i var [: !var execute ;] catch >r 2drop drop undo
r@ failure <> r> and throw then
1 rshift
loop
drop failure throw
then ;
\ some constraints:
: array-constraint! {: xt addr u -- :}
\ make xt a wheninst constraint action for all variables in addr u
u 0 +do
xt addr i th @ constraint!
loop ;
\ alldifferent
: alldifferent-c {: u var addr1 u1 -- :}
\ in the variables in addr1 u1, var has been instantiated to u
addr1 u1 th addr1 u+do
i @ {: vari :}
vari var <> if
vari var-val @ dup u = if failure throw then ( val )
0< if ( ) \ not yet instantiated
1 u lshift vari var-bits @ 2dup and 0= if failure throw then
xor dup pow2? if ( x ) \ only one bit set
ctz vari !var
else
vari var-bits !bt
then ( )
then
then
1 cells +loop ;
: alldifferent ( addr u -- )
2dup [d:d alldifferent-c ;]
rot rot array-constraint! ;
\ ...sum
: arraysum-c {: u var addr1 u1 usum -- :}
\ with var set to u, deal with the constraint that the sum of the
\ variables in addr1 u1 equals usum.
0 0 u1 0 +do ( usum1 var1 )
addr1 i th @ {: vari :}
vari var-val @ dup 0< if ( usum1 var1 vali )
drop if ( usum1 ) \ constraint has >1 free variables, do nothing
drop unloop exit then
vari
else
rot + swap
then
loop
dup if
usum rot - swap !var
else
drop usum <> if failure throw then
then ;
: arraysum ( addr u usum -- )
>r 2dup r> [{: addr u usum :}d addr u usum arraysum-c ;]
rot rot array-constraint! ;
: 3sum ( v1 v2 v3 usum -- )
align here 2>r , , , 2r> 3 rot arraysum ;
: 4sum ( v1 v2 v3 v4 usum -- )
align here 2>r , , , , 2r> 4 rot arraysum ;
: 5sum ( v1 v2 v3 v4 v5 usum -- )
align here 2>r , , , , , 2r> 5 rot arraysum ;
\ Magic Hexagon specific stuff
\ Newsgroups: comp.lang.forth
\ Date: Sun, 12 Feb 2023 02:43:44 -0800 (PST)
\ Message-ID: <7e7a9acd-81f6-4022-b12a-753f3b418308n@googlegroups.com>
\ Subject: Magic Hexagon
\ From: "minf...@arcor.de" <minforth@arcor.de>
\ Another while-away-your-afternoon-teatime puzzle:
\ Place the integers 1..19 in the following Magic Hexagon of rank 3
\ __A_B_C__
\ _D_E_F_G_
\ H_I_J_K_L
\ _M_N_O_P_
\ __Q_R_S__
\ so that the sum of all numbers in a straight line (horizontal and diagonal)
\ is equal to 38.
\ [...]
1 19 domain A
1 19 domain B
1 19 domain C
1 19 domain D
1 19 domain E
1 19 domain F
1 19 domain G
1 19 domain H
1 19 domain I
1 19 domain J
1 19 domain K
1 19 domain L
1 19 domain M
1 19 domain N
1 19 domain O
1 19 domain P
1 19 domain Q
1 19 domain R
1 19 domain S
create vars
A , B , C , D , E , F , G , H , I , J , K , L , M , N , O , P , Q , R , S ,
vars 19 alldifferent
A B C 38 3sum
Q R S 38 3sum
A D H 38 3sum
L P S 38 3sum
C G L 38 3sum
H M Q 38 3sum
D E F G 38 4sum
M N O P 38 4sum
B E I M 38 4sum
G K O R 38 4sum
B F K P 38 4sum
D I N R 38 4sum
H I J K L 38 5sum
C F J N Q 38 5sum
A E J O S 38 5sum
: .var ( var -- )
var-val @ 4 .r ;
: printsolution ( -- )
cr ." " A .var B .var C .var
cr ." " D .var E .var F .var G .var
cr H .var I .var J .var K .var L .var
cr ." " M .var N .var O .var P .var
cr ." " Q .var R .var S .var cr ;
: labeling ( -- )
\ start with the corner variables in 3sums
\ B G P R N D follow from the 3sum constraints
\ then label one other 4sum variable: E
\ I N O K F J follow from the constraints
[: A
[: C
[: L
[: S
[: Q
[: H
[: E
[: printsolution failure throw ;]
label ;]
label ;]
label ;]
label ;]
label ;]
label ;]
label ;]
catch dup failure <> and throw
." no (more) solutions" cr ;