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