1 /*
2 ------------------------------------------------------------------------------
3 By Bob Jenkins, 1989, in association with his thesis project
4 Public Domain
5 ------------------------------------------------------------------------------
6 */
7 #include <stdlib.h>
8 #include <gc.h>
9
10 #include "standard.h"
11 #include "dllink.h"
12 #include "knot.h"
13 #include "order.h"
14
15 /* o_tabs: mark the neighbors and the neighbors of the neighbors */
16 #define o_tabs( k, t, big) \
17 if (1) \
18 { \
19 (t)[(k)->o->c] += (big); \
20 (t)[(k)->o->a->c] += 2; \
21 (t)[(k)->o->z->c] -= 1; \
22 (t)[(k)->u->a->c] += 2; \
23 (t)[(k)->u->z->c] -= 1; \
24 } else
25
26 /* This assumes that every crossing is used.
27 This lists the crossings in an order my algorithm will hopefully like. */
o_order2(crossing * k,word * oldorder,word * order,word crossings)28 static void o_order2(
29 crossing *k,
30 word *oldorder,
31 word *order,
32 word crossings)
33 {
34 word tab[MAXCROSS];
35 word j,
36 *ip,
37 *endp,
38 tmp1,
39 tmp2;
40 crossing *kp,
41 *kp2;
42
43 for (ip = tab, endp = tab+crossings; ip != endp;) *(ip++) = 0;
44 *order = oldorder[crossings-1];
45 for (ip = order+1, endp = order+crossings; ip < endp; ip++)
46 {
47 j = *(ip-1);
48 *ip = j;
49 tab[j] -= 100;
50 kp2 = k+j;
51 kp = k+kp2->o->a->c;
52 o_tabs(kp, tab, 16);
53 kp = k+kp2->o->z->c;
54 o_tabs(kp, tab, 20);
55 kp = k+kp2->u->a->c;
56 o_tabs(kp, tab, 16);
57 kp = k+kp2->u->z->c;
58 o_tabs(kp, tab, 20);
59 tmp1 = *ip;
60 for (j = 0; j < crossings; ++j)
61 {
62 tmp2 = oldorder[crossings-1-j];
63 if (tab[tmp2] > tab[tmp1]) tmp1 = tmp2;
64 }
65 *ip = tmp1;
66 }
67 }
68
69
70 /* This assumes that every crossing is used.
71 This lists the crossings in an order my algorithm will hopefully like. */
o_order1(crossing * k,word * oldorder,word * order,word crossings)72 static void o_order1(crossing *k,
73 word *oldorder,
74 word *order,
75 word crossings)
76 {
77 word tab[MAXCROSS];
78 word j,
79 *ip,
80 *endp,
81 tmp1,
82 tmp2;
83 crossing *kp2;
84
85 for (ip = tab, endp = tab+crossings; ip != endp;) *(ip++) = 0;
86 *order = oldorder[crossings-1];
87 for (ip = order+1, endp = order+crossings; ip != endp; ip++)
88 {
89 j = *(ip-1);
90 *ip = j;
91 tab[j] -= 100;
92 kp2 = k+j;
93 tab[kp2->o->a->c] += 20;
94 tab[kp2->o->z->c] += 20;
95 tab[kp2->u->a->c] += 20;
96 tab[kp2->u->z->c] += 20;
97 tmp1 = *ip;
98 for (j = 0; j < crossings; ++j)
99 {
100 tmp2 = oldorder[crossings-1-j];
101 if (tab[tmp2] > tab[tmp1]) tmp1 = tmp2;
102 }
103 *ip = tmp1;
104 }
105 }
106
107 /**
108 * Make instructions for just adding a crossing to the solved region
109 */
o_add(word * n,dllink ** boundary,word * going_in,crossing * k,word newcross,Instruct * answer)110 static void o_add(word *n, /* in/out: the number of strings in the weave */
111 dllink **boundary,
112 word *going_in, /* in/out: which strings are inputs */
113 crossing *k,
114 word newcross,
115 Instruct *answer)
116 {
117 word i;
118 word old;
119 word go_in;
120 word righthanded;
121 dllink *link; /* link in crossing perpendicular to boundary */
122 word after; /* is the new input after the original string? */
123
124 answer->crossing = newcross;
125 answer->oldn = *n;
126 for (i = 0; i<*n; ++i)
127 {
128 answer->going_in[i] = going_in[i];
129 }
130 /*-------------- Find *old*, try to make it an input rather than an output */
131 /* Imagine crossing c, input 0 and output n attached to c. If you add the
132 crossing at n, n becomes n+1 and you have input n and output n+2. Then
133 the pair of boundary crossings n+2 and 0 are removed, and string 0 becomes
134 string n (really n-1 since things shift to fill in the missing 0).
135 Changing a string from 0 to n-1 is likely to produce lots of bad
136 crossings. If you added the crossing at the input to begin with, the
137 problem would have been avoided. So try to add crossings at inputs. */
138 for (i = *n; boundary[--i]->c != newcross;) ;
139 old = i;
140 if (!going_in[i])
141 {
142 while (i && (boundary[--i]->c != newcross || !going_in[i]));
143 if (boundary[i]->c == newcross && going_in[i]) old = i;
144 }
145 answer->which = old;
146 answer->over = (k[newcross].o == boundary[old]);
147 answer->right = (k[newcross].hand == 1);
148 *n += 2;
149 for (i = *n; --i > old+2;)
150 {
151 boundary[i] = boundary[i-2];
152 going_in[i] = going_in[i-2];
153 }
154 go_in = going_in[old];
155 righthanded = answer->right;
156 link = answer->over ? k[newcross].u : k[newcross].o;
157 going_in[old+1] = go_in;
158 boundary[old+1] = (go_in ? boundary[old]->a : boundary[old]->z);
159
160 /* crossing are labeled counterclockwise */
161 after = (go_in ^ righthanded ^ answer->over);
162
163 if (after)
164 {
165 boundary[old] = link->z;
166 going_in[old] = 0;
167 boundary[old+2] = link->a;
168 going_in[old+2] = 1;
169 }
170 else
171 {
172 boundary[old] = link->a;
173 going_in[old] = 1;
174 boundary[old+2] = link->z;
175 going_in[old+2] = 0;
176 }
177 answer->prev = going_in[old];
178 answer->newn = *n;
179 answer->reductions = 0;
180 }
181
182
183 /**
184 * Make instructions for removing one pair of boundary crossings
185 */
o_delete(word * n,dllink ** boundary,word * going_in,Instruct * answer,word * done,word i)186 static void o_delete(word *n,
187 dllink **boundary,
188 word *going_in,
189 Instruct *answer,
190 word *done,
191 word i)
192 {
193 word j;
194 dllink *l,
195 *m;
196
197 j = (i == 0) ? *n-1 : i-1;
198 l = (going_in[i]) ? boundary[i]->z : boundary[i]->a;
199 m = (going_in[j]) ? boundary[j]->z : boundary[j]->a;
200 if ((l == boundary[j]) && (m == boundary[i]))
201 {
202
203 *done = 0;
204 answer->r0[answer->reductions] = i;
205 answer->r1[answer->reductions] = j;
206 if (i == 0)
207 {
208 for (j = 0; j < (*n)-2; j++)
209 {
210 boundary[j] = boundary[j+1];
211 going_in[j] = going_in[j+1];
212 }
213 }
214 else
215 {
216 for (j = i-1; j < (*n)-2; j++)
217 {
218 boundary[j] = boundary[j+2];
219 going_in[j] = going_in[j+2];
220 }
221 }
222 answer->reductions++;
223 *n -= 2;
224 }
225 }
226
227
228 /* make instructions for handling a single crossing */
o_one_make(word * n,dllink ** boundary,word * going_in,crossing * k,word which,Instruct * answer)229 static void o_one_make(word *n,
230 dllink **boundary,
231 word *going_in,
232 crossing *k,
233 word which,
234 Instruct *answer)
235 {
236 word i, done;
237
238 /* Move one crossing into the solved region */
239 o_add(n, boundary, going_in, k, which, answer);
240
241 /* Join as many adjacent boundary pairs as possible */
242 for (done = 0; !done;)
243 {
244 for (i = *n, done = 1; done && (--i >= 0);)
245 {
246 if (*n == 2) break; /* do not shrink to nothing */
247 o_delete(n, boundary, going_in, answer, &done, i);
248 }
249 }
250 answer->newn = *n;
251 }
252
253
254 /* Make complete instructions for handling all the crossings */
o_make(Link * link,Instruct ** list)255 void o_make(Link *link, Instruct **list)
256 {
257 word order1[MAXCROSS]; /* order of crossings */
258 word order2[MAXCROSS]; /* another order of crossings */
259 dllink *boundary[BIGWEAVE];
260 word going_in[BIGWEAVE];
261 word i, j, n;
262 int num_crossings = link->num_crossings;
263 const crossing *k = link->data;
264 Instruct *l;
265
266 l = (Instruct *)GC_MALLOC(sizeof(Instruct) * num_crossings);
267 for (i = 0; i < num_crossings; order1[i] = i, i++) ;
268 for (i = 0; i < num_crossings; order2[i] = i, i++) ;
269 o_order2(k, order2, order1, num_crossings);
270 o_order1(k, order1, order2, num_crossings);
271 o_order1(k, order2, order1, num_crossings);
272 boundary[0] = k[order1[0]].o;
273 boundary[1] = k[order1[0]].o->z;
274 going_in[0] = 1;
275 going_in[1] = 0;
276 n = 2;
277
278 for (i = 0; i < num_crossings; ++i)
279 o_one_make(&n, boundary, going_in, k, order1[i], (l+i));
280 *list = l;
281 }
282
283
284 /*void o_show(Instruct *l, word num_crossings)
285 {
286 word i;
287 word j;
288 }*/
289
290