pickmove.c revision 1.41 1 /* $NetBSD: pickmove.c,v 1.41 2022/05/21 15:11:24 rillig Exp $ */
2
3 /*
4 * Copyright (c) 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Ralph Campbell.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 /* @(#)pickmove.c 8.2 (Berkeley) 5/3/95 */
37 __RCSID("$NetBSD: pickmove.c,v 1.41 2022/05/21 15:11:24 rillig Exp $");
38
39 #include <stdlib.h>
40 #include <string.h>
41 #include <curses.h>
42 #include <limits.h>
43
44 #include "gomoku.h"
45
46 #define BITS_PER_INT (sizeof(int) * CHAR_BIT)
47 #define MAPSZ (BAREA / BITS_PER_INT)
48
49 #define BIT_SET(a, b) ((a)[(b)/BITS_PER_INT] |= (1 << ((b) % BITS_PER_INT)))
50 #define BIT_CLR(a, b) ((a)[(b)/BITS_PER_INT] &= ~(1 << ((b) % BITS_PER_INT)))
51 #define BIT_TEST(a, b) (((a)[(b)/BITS_PER_INT] & (1 << ((b) % BITS_PER_INT))) != 0)
52
53 /*
54 * This structure is used to store overlap information between frames.
55 */
56 struct overlap_info {
57 int o_intersect; /* intersection spot */
58 u_char o_off; /* offset in frame of intersection */
59 u_char o_frameindex; /* intersection frame index */
60 };
61
62 static struct combostr *hashcombos[FAREA];/* hash list for finding duplicates */
63 static struct combostr *sortcombos; /* combos at higher levels */
64 static int combolen; /* number of combos in sortcombos */
65 static int nextcolor; /* color of next move */
66 static int elistcnt; /* count of struct elist allocated */
67 static int combocnt; /* count of struct combostr allocated */
68 static int forcemap[MAPSZ]; /* map for blocking <1,x> combos */
69 static int tmpmap[MAPSZ]; /* map for blocking <1,x> combos */
70 static int nforce; /* count of opponent <1,x> combos */
71
72 static bool better(const struct spotstr *, const struct spotstr *, int);
73 static void scanframes(int);
74 static void makecombo2(struct combostr *, struct spotstr *, int, int);
75 static void addframes(int);
76 static void makecombo(struct combostr *, struct spotstr *, int, int);
77 static void appendcombo(struct combostr *, int);
78 static void updatecombo(struct combostr *, int);
79 static void makeempty(struct combostr *);
80 static int checkframes(struct combostr *, struct combostr *, struct spotstr *,
81 int, struct overlap_info *);
82 static bool sortcombo(struct combostr **, struct combostr **, struct combostr *);
83 #if !defined(DEBUG)
84 static void printcombo(struct combostr *, char *, size_t);
85 #endif
86
87 int
88 pickmove(int us)
89 {
90 struct spotstr *sp, *sp1, *sp2;
91 union comboval *Ocp, *Tcp;
92 int m;
93
94 /* first move is easy */
95 if (movenum == 1)
96 return PT((BSZ + 1) / 2, (BSZ + 1) / 2);
97
98 /* initialize all the board values */
99 for (unsigned pos = PT(BSZ, BSZ + 1); pos-- > PT(1, 1); ) {
100 sp = &board[pos];
101 sp->s_combo[BLACK].s = 0x601;
102 sp->s_combo[WHITE].s = 0x601;
103 sp->s_level[BLACK] = 255;
104 sp->s_level[WHITE] = 255;
105 sp->s_nforce[BLACK] = 0;
106 sp->s_nforce[WHITE] = 0;
107 sp->s_flags &= ~(FFLAGALL | MFLAGALL);
108 }
109 nforce = 0;
110 memset(forcemap, 0, sizeof(forcemap));
111
112 /* compute new values */
113 nextcolor = us;
114 scanframes(BLACK);
115 scanframes(WHITE);
116
117 /* find the spot with the highest value */
118 unsigned pos = PT(BSZ, BSZ);
119 sp1 = sp2 = &board[pos];
120 for ( ; pos-- > PT(1, 1); ) {
121 sp = &board[pos];
122 if (sp->s_occ != EMPTY)
123 continue;
124 if (debug != 0 && (sp->s_combo[BLACK].c.a == 1 ||
125 sp->s_combo[WHITE].c.a == 1)) {
126 debuglog("- %s %x/%d %d %x/%d %d %d",
127 stoc((int)(sp - board)),
128 sp->s_combo[BLACK].s, sp->s_level[BLACK],
129 sp->s_nforce[BLACK],
130 sp->s_combo[WHITE].s, sp->s_level[WHITE],
131 sp->s_nforce[WHITE],
132 sp->s_wval);
133 }
134 /* pick the best black move */
135 if (better(sp, sp1, BLACK))
136 sp1 = sp;
137 /* pick the best white move */
138 if (better(sp, sp2, WHITE))
139 sp2 = sp;
140 }
141
142 if (debug != 0) {
143 debuglog("B %s %x/%d %d %x/%d %d %d",
144 stoc((int)(sp1 - board)),
145 sp1->s_combo[BLACK].s, sp1->s_level[BLACK],
146 sp1->s_nforce[BLACK],
147 sp1->s_combo[WHITE].s, sp1->s_level[WHITE],
148 sp1->s_nforce[WHITE], sp1->s_wval);
149 debuglog("W %s %x/%d %d %x/%d %d %d",
150 stoc((int)(sp2 - board)),
151 sp2->s_combo[WHITE].s, sp2->s_level[WHITE],
152 sp2->s_nforce[WHITE],
153 sp2->s_combo[BLACK].s, sp2->s_level[BLACK],
154 sp2->s_nforce[BLACK], sp2->s_wval);
155 /*
156 * Check for more than one force that can't
157 * all be blocked with one move.
158 */
159 sp = (us == BLACK) ? sp2 : sp1;
160 m = (int)(sp - board);
161 if (sp->s_combo[us != BLACK ? BLACK : WHITE].c.a == 1 &&
162 !BIT_TEST(forcemap, m))
163 debuglog("*** Can't be blocked");
164 }
165 if (us == BLACK) {
166 Ocp = &sp1->s_combo[BLACK];
167 Tcp = &sp2->s_combo[WHITE];
168 } else {
169 Tcp = &sp1->s_combo[BLACK];
170 Ocp = &sp2->s_combo[WHITE];
171 sp = sp1;
172 sp1 = sp2;
173 sp2 = sp;
174 }
175 /*
176 * Block their combo only if we have to (i.e., if they are one move
177 * away from completing a force, and we don't have a force that
178 * we can complete which takes fewer moves to win).
179 */
180 if (Tcp->c.a <= 1 && (Ocp->c.a > 1 ||
181 Tcp->c.a + Tcp->c.b < Ocp->c.a + Ocp->c.b))
182 return (int)(sp2 - board);
183 return (int)(sp1 - board);
184 }
185
186 /*
187 * Return true if spot 'sp' is better than spot 'sp1' for color 'us'.
188 */
189 static bool
190 better(const struct spotstr *sp, const struct spotstr *sp1, int us)
191 {
192 int them, s, s1;
193
194 if (/* .... */ sp->s_combo[us].s != sp1->s_combo[us].s)
195 return sp->s_combo[us].s < sp1->s_combo[us].s;
196 if (/* .... */ sp->s_level[us] != sp1->s_level[us])
197 return sp->s_level[us] < sp1->s_level[us];
198 if (/* .... */ sp->s_nforce[us] != sp1->s_nforce[us])
199 return sp->s_nforce[us] > sp1->s_nforce[us];
200
201 them = us != BLACK ? BLACK : WHITE;
202 s = (int)(sp - board);
203 s1 = (int)(sp1 - board);
204 if (BIT_TEST(forcemap, s) != BIT_TEST(forcemap, s1))
205 return BIT_TEST(forcemap, s);
206
207 if (/* .... */ sp->s_combo[them].s != sp1->s_combo[them].s)
208 return sp->s_combo[them].s < sp1->s_combo[them].s;
209 if (/* .... */ sp->s_level[them] != sp1->s_level[them])
210 return sp->s_level[them] < sp1->s_level[them];
211 if (/* .... */ sp->s_nforce[them] != sp1->s_nforce[them])
212 return sp->s_nforce[them] > sp1->s_nforce[them];
213
214 if (/* .... */ sp->s_wval != sp1->s_wval)
215 return sp->s_wval > sp1->s_wval;
216
217 return (random() & 1) != 0;
218 }
219
220 static int curcolor; /* implicit parameter to makecombo() */
221 static int curlevel; /* implicit parameter to makecombo() */
222
223 /*
224 * Scan the sorted list of non-empty frames and
225 * update the minimum combo values for each empty spot.
226 * Also, try to combine frames to find more complex (chained) moves.
227 */
228 static void
229 scanframes(int color)
230 {
231 struct combostr *cbp, *ecbp;
232 struct spotstr *sp;
233 union comboval *cp;
234 struct elist *nep;
235 int i, r, d, n;
236 union comboval cb;
237
238 curcolor = color;
239
240 /* check for empty list of frames */
241 cbp = sortframes[color];
242 if (cbp == NULL)
243 return;
244
245 /* quick check for four in a row */
246 sp = &board[cbp->c_vertex];
247 cb.s = sp->s_fval[color][d = cbp->c_dir].s;
248 if (cb.s < 0x101) {
249 d = dd[d];
250 for (i = 5 + cb.c.b; --i >= 0; sp += d) {
251 if (sp->s_occ != EMPTY)
252 continue;
253 sp->s_combo[color].s = cb.s;
254 sp->s_level[color] = 1;
255 }
256 return;
257 }
258
259 /*
260 * Update the minimum combo value for each spot in the frame
261 * and try making all combinations of two frames intersecting at
262 * an empty spot.
263 */
264 n = combolen;
265 ecbp = cbp;
266 do {
267 sp = &board[cbp->c_vertex];
268 cp = &sp->s_fval[color][r = cbp->c_dir];
269 d = dd[r];
270 if (cp->c.b != 0) {
271 /*
272 * Since this is the first spot of an open-ended
273 * frame, we treat it as a closed frame.
274 */
275 cb.c.a = cp->c.a + 1;
276 cb.c.b = 0;
277 if (cb.s < sp->s_combo[color].s) {
278 sp->s_combo[color].s = cb.s;
279 sp->s_level[color] = 1;
280 }
281 /*
282 * Try combining other frames that intersect
283 * at this spot.
284 */
285 makecombo2(cbp, sp, 0, cb.s);
286 if (cp->s != 0x101)
287 cb.s = cp->s;
288 else if (color != nextcolor)
289 memset(tmpmap, 0, sizeof(tmpmap));
290 sp += d;
291 i = 1;
292 } else {
293 cb.s = cp->s;
294 i = 0;
295 }
296 for (; i < 5; i++, sp += d) { /* for each spot */
297 if (sp->s_occ != EMPTY)
298 continue;
299 if (cp->s < sp->s_combo[color].s) {
300 sp->s_combo[color].s = cp->s;
301 sp->s_level[color] = 1;
302 }
303 if (cp->s == 0x101) {
304 sp->s_nforce[color]++;
305 if (color != nextcolor) {
306 n = (int)(sp - board);
307 BIT_SET(tmpmap, n);
308 }
309 }
310 /*
311 * Try combining other frames that intersect
312 * at this spot.
313 */
314 makecombo2(cbp, sp, i, cb.s);
315 }
316 if (cp->s == 0x101 && color != nextcolor) {
317 if (nforce == 0)
318 memcpy(forcemap, tmpmap, sizeof(tmpmap));
319 else {
320 for (i = 0; (unsigned int)i < MAPSZ; i++)
321 forcemap[i] &= tmpmap[i];
322 }
323 }
324 /* mark frame as having been processed */
325 board[cbp->c_vertex].s_flags |= MFLAG << r;
326 } while ((cbp = cbp->c_next) != ecbp);
327
328 /*
329 * Try to make new 3rd level combos, 4th level, etc.
330 * Limit the search depth early in the game.
331 */
332 d = 2;
333 /* LINTED 117: bitwise '>>' on signed value possibly nonportable */
334 while (d <= ((movenum + 1) >> 1) && combolen > n) {
335 if (d >= 9)
336 break; /* Do not think too long. */
337 if (debug != 0) {
338 debuglog("%cL%d %d %d %d", "BW"[color],
339 d, combolen - n, combocnt, elistcnt);
340 refresh();
341 }
342 n = combolen;
343 addframes(d);
344 d++;
345 }
346
347 /* scan for combos at empty spots */
348 for (unsigned pos = PT(BSZ, BSZ + 1); pos-- > PT(1, 1); ) {
349 sp = &board[pos];
350 for (struct elist *ep = sp->s_empty; ep != NULL; ep = nep) {
351 cbp = ep->e_combo;
352 if (cbp->c_combo.s <= sp->s_combo[color].s) {
353 if (cbp->c_combo.s != sp->s_combo[color].s) {
354 sp->s_combo[color].s = cbp->c_combo.s;
355 sp->s_level[color] = cbp->c_nframes;
356 } else if (cbp->c_nframes < sp->s_level[color])
357 sp->s_level[color] = cbp->c_nframes;
358 }
359 nep = ep->e_next;
360 free(ep);
361 elistcnt--;
362 }
363 sp->s_empty = NULL;
364 for (struct elist *ep = sp->s_nempty; ep != NULL; ep = nep) {
365 cbp = ep->e_combo;
366 if (cbp->c_combo.s <= sp->s_combo[color].s) {
367 if (cbp->c_combo.s != sp->s_combo[color].s) {
368 sp->s_combo[color].s = cbp->c_combo.s;
369 sp->s_level[color] = cbp->c_nframes;
370 } else if (cbp->c_nframes < sp->s_level[color])
371 sp->s_level[color] = cbp->c_nframes;
372 }
373 nep = ep->e_next;
374 free(ep);
375 elistcnt--;
376 }
377 sp->s_nempty = NULL;
378 }
379
380 /* remove old combos */
381 if ((cbp = sortcombos) != NULL) {
382 struct combostr *ncbp;
383
384 /* scan the list */
385 ecbp = cbp;
386 do {
387 ncbp = cbp->c_next;
388 free(cbp);
389 combocnt--;
390 } while ((cbp = ncbp) != ecbp);
391 sortcombos = NULL;
392 }
393 combolen = 0;
394
395 #ifdef DEBUG
396 if (combocnt != 0) {
397 debuglog("scanframes: %c combocnt %d", "BW"[color],
398 combocnt);
399 whatsup(0);
400 }
401 if (elistcnt != 0) {
402 debuglog("scanframes: %c elistcnt %d", "BW"[color],
403 elistcnt);
404 whatsup(0);
405 }
406 #endif
407 }
408
409 /*
410 * Compute all level 2 combos of frames intersecting spot 'osp'
411 * within the frame 'ocbp' and combo value 's'.
412 */
413 static void
414 makecombo2(struct combostr *ocbp, struct spotstr *osp, int off, int s)
415 {
416 struct spotstr *fsp;
417 struct combostr *ncbp;
418 int d, c;
419 int baseB, fcnt, emask, bmask, n;
420 union comboval ocb, fcb;
421 struct combostr **scbpp, *fcbp;
422 char tmp[128];
423
424 /* try to combine a new frame with those found so far */
425 ocb.s = s;
426 baseB = ocb.c.a + ocb.c.b - 1;
427 fcnt = ocb.c.a - 2;
428 emask = fcnt != 0 ? ((ocb.c.b != 0 ? 0x1E : 0x1F) & ~(1 << off)) : 0;
429 for (int r = 4; --r >= 0; ) { /* for each direction */
430 /* don't include frames that overlap in the same direction */
431 if (r == ocbp->c_dir)
432 continue;
433 d = dd[r];
434 /*
435 * Frame A combined with B is the same value as B combined with A
436 * so skip frames that have already been processed (MFLAG).
437 * Also skip blocked frames (BFLAG) and frames that are <1,x>
438 * since combining another frame with it isn't valid.
439 */
440 bmask = (BFLAG | FFLAG | MFLAG) << r;
441 fsp = osp;
442 for (int f = 0; f < 5; f++, fsp -= d) { /* for each frame */
443 if (fsp->s_occ == BORDER)
444 break;
445 if ((fsp->s_flags & bmask) != 0)
446 continue;
447
448 /* don't include frames of the wrong color */
449 fcb.s = fsp->s_fval[curcolor][r].s;
450 if (fcb.c.a >= 6)
451 continue;
452
453 /*
454 * Get the combo value for this frame.
455 * If this is the end point of the frame,
456 * use the closed ended value for the frame.
457 */
458 if ((f == 0 && fcb.c.b != 0) || fcb.s == 0x101) {
459 fcb.c.a++;
460 fcb.c.b = 0;
461 }
462
463 /* compute combo value */
464 c = fcb.c.a + ocb.c.a - 3;
465 if (c > 4)
466 continue;
467 n = fcb.c.a + fcb.c.b - 1;
468 if (baseB < n)
469 n = baseB;
470
471 /* make a new combo! */
472 ncbp = (struct combostr *)malloc(sizeof(struct combostr) +
473 2 * sizeof(struct combostr *));
474 if (ncbp == NULL)
475 panic("Out of memory!");
476 scbpp = (void *)(ncbp + 1);
477 fcbp = fsp->s_frame[r];
478 if (ocbp < fcbp) {
479 scbpp[0] = ocbp;
480 scbpp[1] = fcbp;
481 } else {
482 scbpp[0] = fcbp;
483 scbpp[1] = ocbp;
484 }
485 ncbp->c_combo.c.a = c;
486 ncbp->c_combo.c.b = n;
487 ncbp->c_link[0] = ocbp;
488 ncbp->c_link[1] = fcbp;
489 ncbp->c_linkv[0].s = ocb.s;
490 ncbp->c_linkv[1].s = fcb.s;
491 ncbp->c_voff[0] = off;
492 ncbp->c_voff[1] = f;
493 ncbp->c_vertex = (u_short)(osp - board);
494 ncbp->c_nframes = 2;
495 ncbp->c_dir = 0;
496 ncbp->c_frameindex = 0;
497 ncbp->c_flags = ocb.c.b != 0 ? C_OPEN_0 : 0;
498 if (fcb.c.b != 0)
499 ncbp->c_flags |= C_OPEN_1;
500 ncbp->c_framecnt[0] = fcnt;
501 ncbp->c_emask[0] = emask;
502 ncbp->c_framecnt[1] = fcb.c.a - 2;
503 ncbp->c_emask[1] = ncbp->c_framecnt[1] != 0 ?
504 ((fcb.c.b != 0 ? 0x1E : 0x1F) & ~(1 << f)) : 0;
505 combocnt++;
506
507 if ((c == 1 && debug > 1) || debug > 3) {
508 debuglog("%c c %d %d m %x %x o %d %d",
509 "bw"[curcolor],
510 ncbp->c_framecnt[0], ncbp->c_framecnt[1],
511 ncbp->c_emask[0], ncbp->c_emask[1],
512 ncbp->c_voff[0], ncbp->c_voff[1]);
513 printcombo(ncbp, tmp, sizeof(tmp));
514 debuglog("%s", tmp);
515 }
516 if (c > 1) {
517 /* record the empty spots that will complete this combo */
518 makeempty(ncbp);
519
520 /* add the new combo to the end of the list */
521 appendcombo(ncbp, curcolor);
522 } else {
523 updatecombo(ncbp, curcolor);
524 free(ncbp);
525 combocnt--;
526 }
527 #ifdef DEBUG
528 if ((c == 1 && debug > 1) || debug > 5) {
529 markcombo(ncbp);
530 bdisp();
531 whatsup(0);
532 clearcombo(ncbp, 0);
533 }
534 #endif /* DEBUG */
535 }
536 }
537 }
538
539 /*
540 * Scan the sorted list of frames and try to add a frame to
541 * combinations of 'level' number of frames.
542 */
543 static void
544 addframes(int level)
545 {
546 struct combostr *cbp, *ecbp;
547 struct spotstr *sp, *fsp;
548 struct elist *nep;
549 int i, r, d;
550 struct combostr **cbpp, *pcbp;
551 union comboval fcb, cb;
552
553 curlevel = level;
554
555 /* scan for combos at empty spots */
556 i = curcolor;
557 for (unsigned pos = PT(BSZ, BSZ + 1); pos-- > PT(1, 1); ) {
558 sp = &board[pos];
559 for (struct elist *ep = sp->s_empty; ep != NULL; ep = nep) {
560 cbp = ep->e_combo;
561 if (cbp->c_combo.s <= sp->s_combo[i].s) {
562 if (cbp->c_combo.s != sp->s_combo[i].s) {
563 sp->s_combo[i].s = cbp->c_combo.s;
564 sp->s_level[i] = cbp->c_nframes;
565 } else if (cbp->c_nframes < sp->s_level[i])
566 sp->s_level[i] = cbp->c_nframes;
567 }
568 nep = ep->e_next;
569 free(ep);
570 elistcnt--;
571 }
572 sp->s_empty = sp->s_nempty;
573 sp->s_nempty = NULL;
574 }
575
576 /* try to add frames to the uncompleted combos at level curlevel */
577 cbp = ecbp = sortframes[curcolor];
578 do {
579 fsp = &board[cbp->c_vertex];
580 r = cbp->c_dir;
581 /* skip frames that are part of a <1,x> combo */
582 if ((fsp->s_flags & (FFLAG << r)) != 0)
583 continue;
584
585 /*
586 * Don't include <1,x> combo frames,
587 * treat it as a closed three in a row instead.
588 */
589 fcb.s = fsp->s_fval[curcolor][r].s;
590 if (fcb.s == 0x101)
591 fcb.s = 0x200;
592
593 /*
594 * If this is an open-ended frame, use
595 * the combo value with the end closed.
596 */
597 if (fsp->s_occ == EMPTY) {
598 if (fcb.c.b != 0) {
599 cb.c.a = fcb.c.a + 1;
600 cb.c.b = 0;
601 } else
602 cb.s = fcb.s;
603 makecombo(cbp, fsp, 0, cb.s);
604 }
605
606 /*
607 * The next four spots are handled the same for both
608 * open and closed ended frames.
609 */
610 d = dd[r];
611 sp = fsp + d;
612 for (i = 1; i < 5; i++, sp += d) {
613 if (sp->s_occ != EMPTY)
614 continue;
615 makecombo(cbp, sp, i, fcb.s);
616 }
617 } while ((cbp = cbp->c_next) != ecbp);
618
619 /* put all the combos in the hash list on the sorted list */
620 cbpp = &hashcombos[FAREA];
621 do {
622 cbp = *--cbpp;
623 if (cbp == NULL)
624 continue;
625 *cbpp = NULL;
626 ecbp = sortcombos;
627 if (ecbp == NULL)
628 sortcombos = cbp;
629 else {
630 /* append to sort list */
631 pcbp = ecbp->c_prev;
632 pcbp->c_next = cbp;
633 ecbp->c_prev = cbp->c_prev;
634 cbp->c_prev->c_next = ecbp;
635 cbp->c_prev = pcbp;
636 }
637 } while (cbpp != hashcombos);
638 }
639
640 /*
641 * Compute all level N combos of frames intersecting spot 'osp'
642 * within the frame 'ocbp' and combo value 's'.
643 */
644 static void
645 makecombo(struct combostr *ocbp, struct spotstr *osp, int off, int s)
646 {
647 struct combostr *cbp, *ncbp;
648 struct spotstr *sp;
649 int n, c;
650 struct combostr **scbpp;
651 int baseB, fcnt, emask, verts;
652 union comboval ocb;
653 struct overlap_info vertices[1];
654 char tmp[128];
655
656 /*
657 * XXX: when I made functions static gcc started warning about
658 * some members of vertices[0] maybe being used uninitialized.
659 * For now, I'm just going to clear it rather than wade through
660 * the logic to find out whether gcc or the code is wrong. I
661 * wouldn't be surprised if it were the code though. - dholland
662 */
663 memset(vertices, 0, sizeof(vertices));
664
665 ocb.s = s;
666 baseB = ocb.c.a + ocb.c.b - 1;
667 fcnt = ocb.c.a - 2;
668 emask = fcnt != 0 ? ((ocb.c.b != 0 ? 0x1E : 0x1F) & ~(1 << off)) : 0;
669 for (struct elist *ep = osp->s_empty; ep != NULL; ep = ep->e_next) {
670 /* check for various kinds of overlap */
671 cbp = ep->e_combo;
672 verts = checkframes(cbp, ocbp, osp, s, vertices);
673 if (verts < 0)
674 continue;
675
676 /* check to see if this frame forms a valid loop */
677 if (verts > 0) {
678 sp = &board[vertices[0].o_intersect];
679 #ifdef DEBUG
680 if (sp->s_occ != EMPTY) {
681 debuglog("loop: %c %s", "BW"[curcolor],
682 stoc((int)(sp - board)));
683 whatsup(0);
684 }
685 #endif
686 /*
687 * It is a valid loop if the intersection spot
688 * of the frame we are trying to attach is one
689 * of the completion spots of the combostr
690 * we are trying to attach the frame to.
691 */
692 for (struct elist *nep = sp->s_empty;
693 nep != NULL; nep = nep->e_next) {
694 if (nep->e_combo == cbp)
695 goto fnd;
696 if (nep->e_combo->c_nframes < cbp->c_nframes)
697 break;
698 }
699 /* frame overlaps but not at a valid spot */
700 continue;
701 fnd:
702 ;
703 }
704
705 /* compute the first half of the combo value */
706 c = cbp->c_combo.c.a + ocb.c.a - verts - 3;
707 if (c > 4)
708 continue;
709
710 /* compute the second half of the combo value */
711 n = ep->e_fval.c.a + ep->e_fval.c.b - 1;
712 if (baseB < n)
713 n = baseB;
714
715 /* make a new combo! */
716 ncbp = (struct combostr *)malloc(sizeof(struct combostr) +
717 (cbp->c_nframes + 1) * sizeof(struct combostr *));
718 if (ncbp == NULL)
719 panic("Out of memory!");
720 scbpp = (void *)(ncbp + 1);
721 if (sortcombo(scbpp, (void *)(cbp + 1), ocbp)) {
722 free(ncbp);
723 continue;
724 }
725 combocnt++;
726
727 ncbp->c_combo.c.a = c;
728 ncbp->c_combo.c.b = n;
729 ncbp->c_link[0] = cbp;
730 ncbp->c_link[1] = ocbp;
731 ncbp->c_linkv[1].s = ocb.s;
732 ncbp->c_voff[1] = off;
733 ncbp->c_vertex = (u_short)(osp - board);
734 ncbp->c_nframes = cbp->c_nframes + 1;
735 ncbp->c_flags = ocb.c.b != 0 ? C_OPEN_1 : 0;
736 ncbp->c_frameindex = ep->e_frameindex;
737 /*
738 * Update the completion spot mask of the frame we
739 * are attaching 'ocbp' to so the intersection isn't
740 * listed twice.
741 */
742 ncbp->c_framecnt[0] = ep->e_framecnt;
743 ncbp->c_emask[0] = ep->e_emask;
744 if (verts != 0) {
745 ncbp->c_flags |= C_LOOP;
746 ncbp->c_dir = vertices[0].o_frameindex;
747 ncbp->c_framecnt[1] = fcnt - 1;
748 if (ncbp->c_framecnt[1] != 0) {
749 n = (vertices[0].o_intersect - ocbp->c_vertex) /
750 dd[ocbp->c_dir];
751 ncbp->c_emask[1] = emask & ~(1 << n);
752 } else
753 ncbp->c_emask[1] = 0;
754 ncbp->c_voff[0] = vertices[0].o_off;
755 } else {
756 ncbp->c_dir = 0;
757 ncbp->c_framecnt[1] = fcnt;
758 ncbp->c_emask[1] = emask;
759 ncbp->c_voff[0] = ep->e_off;
760 }
761
762 if ((c == 1 && debug > 1) || debug > 3) {
763 debuglog("%c v%d i%d d%d c %d %d m %x %x o %d %d",
764 "bw"[curcolor], verts, ncbp->c_frameindex, ncbp->c_dir,
765 ncbp->c_framecnt[0], ncbp->c_framecnt[1],
766 ncbp->c_emask[0], ncbp->c_emask[1],
767 ncbp->c_voff[0], ncbp->c_voff[1]);
768 printcombo(ncbp, tmp, sizeof(tmp));
769 debuglog("%s", tmp);
770 }
771 if (c > 1) {
772 /* record the empty spots that will complete this combo */
773 makeempty(ncbp);
774 combolen++;
775 } else {
776 /* update board values */
777 updatecombo(ncbp, curcolor);
778 }
779 #ifdef DEBUG
780 if ((c == 1 && debug > 1) || debug > 4) {
781 markcombo(ncbp);
782 bdisp();
783 whatsup(0);
784 clearcombo(ncbp, 0);
785 }
786 #endif /* DEBUG */
787 }
788 }
789
790 #define MAXDEPTH 100
791 static struct elist einfo[MAXDEPTH];
792 static struct combostr *ecombo[MAXDEPTH]; /* separate from elist to save space */
793
794 /*
795 * Add the combostr 'ocbp' to the empty spots list for each empty spot
796 * in 'ocbp' that will complete the combo.
797 */
798 static void
799 makeempty(struct combostr *ocbp)
800 {
801 struct combostr *cbp, **cbpp;
802 struct elist *ep, *nep;
803 struct spotstr *sp;
804 int s, d, m, emask, i;
805 int nframes;
806 char tmp[128];
807
808 if (debug > 2) {
809 printcombo(ocbp, tmp, sizeof(tmp));
810 debuglog("E%c %s", "bw"[curcolor], tmp);
811 }
812
813 /* should never happen but check anyway */
814 if ((nframes = ocbp->c_nframes) >= MAXDEPTH)
815 return;
816
817 /*
818 * The lower level combo can be pointed to by more than one
819 * higher level 'struct combostr' so we can't modify the
820 * lower level. Therefore, higher level combos store the
821 * real mask of the lower level frame in c_emask[0] and the
822 * frame number in c_frameindex.
823 *
824 * First we traverse the tree from top to bottom and save the
825 * connection info. Then we traverse the tree from bottom to
826 * top overwriting lower levels with the newer emask information.
827 */
828 ep = &einfo[nframes];
829 cbpp = &ecombo[nframes];
830 for (cbp = ocbp; cbp->c_link[1] != NULL; cbp = cbp->c_link[0]) {
831 ep--;
832 ep->e_combo = cbp;
833 *--cbpp = cbp->c_link[1];
834 ep->e_off = cbp->c_voff[1];
835 ep->e_frameindex = cbp->c_frameindex;
836 ep->e_fval.s = cbp->c_linkv[1].s;
837 ep->e_framecnt = cbp->c_framecnt[1];
838 ep->e_emask = cbp->c_emask[1];
839 }
840 cbp = ep->e_combo;
841 ep--;
842 ep->e_combo = cbp;
843 *--cbpp = cbp->c_link[0];
844 ep->e_off = cbp->c_voff[0];
845 ep->e_frameindex = 0;
846 ep->e_fval.s = cbp->c_linkv[0].s;
847 ep->e_framecnt = cbp->c_framecnt[0];
848 ep->e_emask = cbp->c_emask[0];
849
850 /* now update the emask info */
851 s = 0;
852 for (i = 2, ep += 2; i < nframes; i++, ep++) {
853 cbp = ep->e_combo;
854 nep = &einfo[ep->e_frameindex];
855 nep->e_framecnt = cbp->c_framecnt[0];
856 nep->e_emask = cbp->c_emask[0];
857
858 if ((cbp->c_flags & C_LOOP) != 0) {
859 s++;
860 /*
861 * Account for the fact that this frame connects
862 * to a previous one (thus forming a loop).
863 */
864 nep = &einfo[cbp->c_dir];
865 if (--nep->e_framecnt != 0)
866 nep->e_emask &= ~(1 << cbp->c_voff[0]);
867 else
868 nep->e_emask = 0;
869 }
870 }
871
872 /*
873 * We only need to update the emask values of "complete" loops
874 * to include the intersection spots.
875 */
876 if (s != 0 && ocbp->c_combo.c.a == 2) {
877 /* process loops from the top down */
878 ep = &einfo[nframes];
879 do {
880 ep--;
881 cbp = ep->e_combo;
882 if ((cbp->c_flags & C_LOOP) == 0)
883 continue;
884
885 /*
886 * Update the emask values to include the
887 * intersection spots.
888 */
889 nep = &einfo[cbp->c_dir];
890 nep->e_framecnt = 1;
891 nep->e_emask = 1 << cbp->c_voff[0];
892 ep->e_framecnt = 1;
893 ep->e_emask = 1 << ep->e_off;
894 ep = &einfo[ep->e_frameindex];
895 do {
896 ep->e_framecnt = 1;
897 ep->e_emask = 1 << ep->e_off;
898 ep = &einfo[ep->e_frameindex];
899 } while (ep > nep);
900 } while (ep != einfo);
901 }
902
903 /* check all the frames for completion spots */
904 for (i = 0, ep = einfo, cbpp = ecombo; i < nframes; i++, ep++, cbpp++) {
905 /* skip this frame if there are no incomplete spots in it */
906 if ((emask = ep->e_emask) == 0)
907 continue;
908 cbp = *cbpp;
909 sp = &board[cbp->c_vertex];
910 d = dd[cbp->c_dir];
911 for (s = 0, m = 1; s < 5; s++, sp += d, m <<= 1) {
912 if (sp->s_occ != EMPTY || (emask & m) == 0)
913 continue;
914
915 /* add the combo to the list of empty spots */
916 nep = (struct elist *)malloc(sizeof(struct elist));
917 if (nep == NULL)
918 panic("Out of memory!");
919 nep->e_combo = ocbp;
920 nep->e_off = s;
921 nep->e_frameindex = i;
922 if (ep->e_framecnt > 1) {
923 nep->e_framecnt = ep->e_framecnt - 1;
924 nep->e_emask = emask & ~m;
925 } else {
926 nep->e_framecnt = 0;
927 nep->e_emask = 0;
928 }
929 nep->e_fval.s = ep->e_fval.s;
930 if (debug > 2) {
931 debuglog("e %s o%d i%d c%d m%x %x",
932 stoc((int)(sp - board)),
933 nep->e_off,
934 nep->e_frameindex,
935 nep->e_framecnt,
936 nep->e_emask,
937 nep->e_fval.s);
938 }
939
940 /* sort by the number of frames in the combo */
941 nep->e_next = sp->s_nempty;
942 sp->s_nempty = nep;
943 elistcnt++;
944 }
945 }
946 }
947
948 /*
949 * Update the board value based on the combostr.
950 * This is called only if 'cbp' is a <1,x> combo.
951 * We handle things differently depending on whether the next move
952 * would be trying to "complete" the combo or trying to block it.
953 */
954 static void
955 updatecombo(struct combostr *cbp, int color)
956 {
957 struct spotstr *sp;
958 struct combostr *tcbp;
959 int d;
960 int nframes, flags, s;
961 union comboval cb;
962
963 flags = 0;
964 /* save the top level value for the whole combo */
965 cb.c.a = cbp->c_combo.c.a;
966 nframes = cbp->c_nframes;
967
968 if (color != nextcolor)
969 memset(tmpmap, 0, sizeof(tmpmap));
970
971 for (; (tcbp = cbp->c_link[1]) != NULL; cbp = cbp->c_link[0]) {
972 flags = cbp->c_flags;
973 cb.c.b = cbp->c_combo.c.b;
974 if (color == nextcolor) {
975 /* update the board value for the vertex */
976 sp = &board[cbp->c_vertex];
977 sp->s_nforce[color]++;
978 if (cb.s <= sp->s_combo[color].s) {
979 if (cb.s != sp->s_combo[color].s) {
980 sp->s_combo[color].s = cb.s;
981 sp->s_level[color] = nframes;
982 } else if (nframes < sp->s_level[color])
983 sp->s_level[color] = nframes;
984 }
985 } else {
986 /* update the board values for each spot in frame */
987 sp = &board[s = tcbp->c_vertex];
988 d = dd[tcbp->c_dir];
989 int i = (flags & C_OPEN_1) != 0 ? 6 : 5;
990 for (; --i >= 0; sp += d, s += d) {
991 if (sp->s_occ != EMPTY)
992 continue;
993 sp->s_nforce[color]++;
994 if (cb.s <= sp->s_combo[color].s) {
995 if (cb.s != sp->s_combo[color].s) {
996 sp->s_combo[color].s = cb.s;
997 sp->s_level[color] = nframes;
998 } else if (nframes < sp->s_level[color])
999 sp->s_level[color] = nframes;
1000 }
1001 BIT_SET(tmpmap, s);
1002 }
1003 }
1004
1005 /* mark the frame as being part of a <1,x> combo */
1006 board[tcbp->c_vertex].s_flags |= FFLAG << tcbp->c_dir;
1007 }
1008
1009 if (color != nextcolor) {
1010 /* update the board values for each spot in frame */
1011 sp = &board[s = cbp->c_vertex];
1012 d = dd[cbp->c_dir];
1013 int i = (flags & C_OPEN_0) != 0 ? 6 : 5;
1014 for (; --i >= 0; sp += d, s += d) {
1015 if (sp->s_occ != EMPTY)
1016 continue;
1017 sp->s_nforce[color]++;
1018 if (cb.s <= sp->s_combo[color].s) {
1019 if (cb.s != sp->s_combo[color].s) {
1020 sp->s_combo[color].s = cb.s;
1021 sp->s_level[color] = nframes;
1022 } else if (nframes < sp->s_level[color])
1023 sp->s_level[color] = nframes;
1024 }
1025 BIT_SET(tmpmap, s);
1026 }
1027 if (nforce == 0)
1028 memcpy(forcemap, tmpmap, sizeof(tmpmap));
1029 else {
1030 for (i = 0; (unsigned int)i < MAPSZ; i++)
1031 forcemap[i] &= tmpmap[i];
1032 }
1033 nforce++;
1034 }
1035
1036 /* mark the frame as being part of a <1,x> combo */
1037 board[cbp->c_vertex].s_flags |= FFLAG << cbp->c_dir;
1038 }
1039
1040 /*
1041 * Add combo to the end of the list.
1042 */
1043 static void
1044 appendcombo(struct combostr *cbp, int color __unused)
1045 {
1046 struct combostr *pcbp, *ncbp;
1047
1048 combolen++;
1049 ncbp = sortcombos;
1050 if (ncbp == NULL) {
1051 sortcombos = cbp;
1052 cbp->c_next = cbp;
1053 cbp->c_prev = cbp;
1054 return;
1055 }
1056 pcbp = ncbp->c_prev;
1057 cbp->c_next = ncbp;
1058 cbp->c_prev = pcbp;
1059 ncbp->c_prev = cbp;
1060 pcbp->c_next = cbp;
1061 }
1062
1063 /*
1064 * Return zero if it is valid to combine frame 'fcbp' with the frames
1065 * in 'cbp' and forms a linked chain of frames (i.e., a tree; no loops).
1066 * Return positive if combining frame 'fcbp' to the frames in 'cbp'
1067 * would form some kind of valid loop. Also return the intersection spots
1068 * in 'vertices[]' beside the known intersection at spot 'osp'.
1069 * Return -1 if 'fcbp' should not be combined with 'cbp'.
1070 * 's' is the combo value for frame 'fcpb'.
1071 */
1072 static int
1073 checkframes(struct combostr *cbp, struct combostr *fcbp, struct spotstr *osp,
1074 int s, struct overlap_info *vertices)
1075 {
1076 struct combostr *tcbp, *lcbp;
1077 int i, n, mask, flags, verts, myindex, fcnt;
1078 union comboval cb;
1079 u_char *str;
1080 short *ip;
1081
1082 lcbp = NULL;
1083 flags = 0;
1084
1085 cb.s = s;
1086 fcnt = cb.c.a - 2;
1087 verts = 0;
1088 myindex = cbp->c_nframes;
1089 n = (int)(fcbp - frames) * FAREA;
1090 str = &overlap[n];
1091 ip = &intersect[n];
1092 /*
1093 * i == which overlap bit to test based on whether 'fcbp' is
1094 * an open or closed frame.
1095 */
1096 i = cb.c.b != 0 ? 2 : 0;
1097 for (; (tcbp = cbp->c_link[1]) != NULL;
1098 lcbp = cbp, cbp = cbp->c_link[0]) {
1099 if (tcbp == fcbp)
1100 return -1; /* fcbp is already included */
1101
1102 /* check for intersection of 'tcbp' with 'fcbp' */
1103 myindex--;
1104 mask = str[tcbp - frames];
1105 flags = cbp->c_flags;
1106 n = i + ((flags & C_OPEN_1) != 0 ? 1 : 0);
1107 if ((mask & (1 << n)) != 0) {
1108 /*
1109 * The two frames are not independent if they
1110 * both lie in the same line and intersect at
1111 * more than one point.
1112 */
1113 if (tcbp->c_dir == fcbp->c_dir &&
1114 (mask & (0x10 << n)) != 0)
1115 return -1;
1116 /*
1117 * If this is not the spot we are attaching
1118 * 'fcbp' to, and it is a reasonable intersection
1119 * spot, then there might be a loop.
1120 */
1121 n = ip[tcbp - frames];
1122 if (osp != &board[n]) {
1123 /* check to see if this is a valid loop */
1124 if (verts != 0)
1125 return -1;
1126 if (fcnt == 0 || cbp->c_framecnt[1] == 0)
1127 return -1;
1128 /*
1129 * Check to be sure the intersection is not
1130 * one of the end points if it is an
1131 * open-ended frame.
1132 */
1133 if ((flags & C_OPEN_1) != 0 &&
1134 (n == tcbp->c_vertex ||
1135 n == tcbp->c_vertex + 5 * dd[tcbp->c_dir]))
1136 return -1; /* invalid overlap */
1137 if (cb.c.b != 0 &&
1138 (n == fcbp->c_vertex ||
1139 n == fcbp->c_vertex + 5 * dd[fcbp->c_dir]))
1140 return -1; /* invalid overlap */
1141
1142 vertices->o_intersect = n;
1143 vertices->o_off = (n - tcbp->c_vertex) /
1144 dd[tcbp->c_dir];
1145 vertices->o_frameindex = myindex;
1146 verts++;
1147 }
1148 }
1149 n = i + ((flags & C_OPEN_0) != 0 ? 1 : 0);
1150 }
1151 if (cbp == fcbp)
1152 return -1; /* fcbp is already included */
1153
1154 /* check for intersection of 'cbp' with 'fcbp' */
1155 mask = str[cbp - frames];
1156 if ((mask & (1 << n)) != 0) {
1157 /*
1158 * The two frames are not independent if they
1159 * both lie in the same line and intersect at
1160 * more than one point.
1161 */
1162 if (cbp->c_dir == fcbp->c_dir && (mask & (0x10 << n)) != 0)
1163 return -1;
1164 /*
1165 * If this is not the spot we are attaching
1166 * 'fcbp' to, and it is a reasonable intersection
1167 * spot, then there might be a loop.
1168 */
1169 n = ip[cbp - frames];
1170 if (osp != &board[n]) {
1171 /* check to see if this is a valid loop */
1172 if (verts != 0)
1173 return -1;
1174 if (fcnt == 0 || lcbp->c_framecnt[0] == 0)
1175 return -1;
1176 /*
1177 * Check to be sure the intersection is not
1178 * one of the end points if it is an open-ended
1179 * frame.
1180 */
1181 if ((flags & C_OPEN_0) != 0 &&
1182 (n == cbp->c_vertex ||
1183 n == cbp->c_vertex + 5 * dd[cbp->c_dir]))
1184 return -1; /* invalid overlap */
1185 if (cb.c.b != 0 &&
1186 (n == fcbp->c_vertex ||
1187 n == fcbp->c_vertex + 5 * dd[fcbp->c_dir]))
1188 return -1; /* invalid overlap */
1189
1190 vertices->o_intersect = n;
1191 vertices->o_off = (n - cbp->c_vertex) /
1192 dd[cbp->c_dir];
1193 vertices->o_frameindex = 0;
1194 verts++;
1195 }
1196 }
1197 return verts;
1198 }
1199
1200 /*
1201 * Merge sort the frame 'fcbp' and the sorted list of frames 'cbpp' and
1202 * store the result in 'scbpp'. 'curlevel' is the size of the 'cbpp' array.
1203 * Return true if this list of frames is already in the hash list.
1204 * Otherwise, add the new combo to the hash list.
1205 */
1206 static bool
1207 sortcombo(struct combostr **scbpp, struct combostr **cbpp,
1208 struct combostr *fcbp)
1209 {
1210 struct combostr **spp, **cpp;
1211 struct combostr *cbp, *ecbp;
1212 int n, inx;
1213
1214 #ifdef DEBUG
1215 if (debug > 3) {
1216 char buf[128];
1217 size_t pos;
1218
1219 debuglog("sortc: %s%c l%d", stoc(fcbp->c_vertex),
1220 pdir[fcbp->c_dir], curlevel);
1221 pos = 0;
1222 for (cpp = cbpp; cpp < cbpp + curlevel; cpp++) {
1223 snprintf(buf + pos, sizeof(buf) - pos, " %s%c",
1224 stoc((*cpp)->c_vertex), pdir[(*cpp)->c_dir]);
1225 pos += strlen(buf + pos);
1226 }
1227 debuglog("%s", buf);
1228 }
1229 #endif /* DEBUG */
1230
1231 /* first build the new sorted list */
1232 n = curlevel + 1;
1233 spp = scbpp + n;
1234 cpp = cbpp + curlevel;
1235 do {
1236 cpp--;
1237 if (fcbp > *cpp) {
1238 *--spp = fcbp;
1239 do {
1240 *--spp = *cpp;
1241 } while (cpp-- != cbpp);
1242 goto inserted;
1243 }
1244 *--spp = *cpp;
1245 } while (cpp != cbpp);
1246 *--spp = fcbp;
1247 inserted:
1248
1249 /* now check to see if this list of frames has already been seen */
1250 cbp = hashcombos[inx = (int)(*scbpp - frames)];
1251 if (cbp == NULL) {
1252 /*
1253 * Easy case, this list hasn't been seen.
1254 * Add it to the hash list.
1255 */
1256 fcbp = (void *)((char *)scbpp - sizeof(struct combostr));
1257 hashcombos[inx] = fcbp;
1258 fcbp->c_next = fcbp->c_prev = fcbp;
1259 return false;
1260 }
1261 ecbp = cbp;
1262 do {
1263 cbpp = (void *)(cbp + 1);
1264 cpp = cbpp + n;
1265 spp = scbpp + n;
1266 cbpp++; /* first frame is always the same */
1267 do {
1268 if (*--spp != *--cpp)
1269 goto next;
1270 } while (cpp != cbpp);
1271 /* we found a match */
1272 #ifdef DEBUG
1273 if (debug > 3) {
1274 char buf[128];
1275 size_t pos;
1276
1277 debuglog("sort1: n%d", n);
1278 pos = 0;
1279 for (cpp = scbpp; cpp < scbpp + n; cpp++) {
1280 snprintf(buf + pos, sizeof(buf) - pos, " %s%c",
1281 stoc((*cpp)->c_vertex),
1282 pdir[(*cpp)->c_dir]);
1283 pos += strlen(buf + pos);
1284 }
1285 debuglog("%s", buf);
1286 printcombo(cbp, buf, sizeof(buf));
1287 debuglog("%s", buf);
1288 cbpp--;
1289 pos = 0;
1290 for (cpp = cbpp; cpp < cbpp + n; cpp++) {
1291 snprintf(buf + pos, sizeof(buf) - pos, " %s%c",
1292 stoc((*cpp)->c_vertex),
1293 pdir[(*cpp)->c_dir]);
1294 pos += strlen(buf + pos);
1295 }
1296 debuglog("%s", buf);
1297 }
1298 #endif /* DEBUG */
1299 return true;
1300 next:
1301 ;
1302 } while ((cbp = cbp->c_next) != ecbp);
1303 /*
1304 * This list of frames hasn't been seen.
1305 * Add it to the hash list.
1306 */
1307 ecbp = cbp->c_prev;
1308 fcbp = (void *)((char *)scbpp - sizeof(struct combostr));
1309 fcbp->c_next = cbp;
1310 fcbp->c_prev = ecbp;
1311 cbp->c_prev = fcbp;
1312 ecbp->c_next = fcbp;
1313 return false;
1314 }
1315
1316 /*
1317 * Print the combo into string buffer 'buf'.
1318 */
1319 #if !defined(DEBUG)
1320 static
1321 #endif
1322 void
1323 printcombo(struct combostr *cbp, char *buf, size_t max)
1324 {
1325 struct combostr *tcbp;
1326 size_t pos = 0;
1327
1328 snprintf(buf + pos, max - pos, "%x/%d",
1329 cbp->c_combo.s, cbp->c_nframes);
1330 pos += strlen(buf + pos);
1331
1332 for (; (tcbp = cbp->c_link[1]) != NULL; cbp = cbp->c_link[0]) {
1333 snprintf(buf + pos, max - pos, " %s%c%x",
1334 stoc(tcbp->c_vertex), pdir[tcbp->c_dir], cbp->c_flags);
1335 pos += strlen(buf + pos);
1336 }
1337 snprintf(buf + pos, max - pos, " %s%c",
1338 stoc(cbp->c_vertex), pdir[cbp->c_dir]);
1339 }
1340
1341 #ifdef DEBUG
1342 void
1343 markcombo(struct combostr *ocbp)
1344 {
1345 struct combostr *cbp, **cbpp;
1346 struct elist *ep, *nep;
1347 struct spotstr *sp;
1348 int s, d, m, i;
1349 int nframes;
1350 int cmask, omask;
1351
1352 /* should never happen but check anyway */
1353 if ((nframes = ocbp->c_nframes) >= MAXDEPTH)
1354 return;
1355
1356 /*
1357 * The lower level combo can be pointed to by more than one
1358 * higher level 'struct combostr' so we can't modify the
1359 * lower level. Therefore, higher level combos store the
1360 * real mask of the lower level frame in c_emask[0] and the
1361 * frame number in c_frameindex.
1362 *
1363 * First we traverse the tree from top to bottom and save the
1364 * connection info. Then we traverse the tree from bottom to
1365 * top overwriting lower levels with the newer emask information.
1366 */
1367 ep = &einfo[nframes];
1368 cbpp = &ecombo[nframes];
1369 for (cbp = ocbp; cbp->c_link[1] != NULL; cbp = cbp->c_link[0]) {
1370 ep--;
1371 ep->e_combo = cbp;
1372 *--cbpp = cbp->c_link[1];
1373 ep->e_off = cbp->c_voff[1];
1374 ep->e_frameindex = cbp->c_frameindex;
1375 ep->e_fval.s = cbp->c_linkv[1].s;
1376 ep->e_framecnt = cbp->c_framecnt[1];
1377 ep->e_emask = cbp->c_emask[1];
1378 }
1379 cbp = ep->e_combo;
1380 ep--;
1381 ep->e_combo = cbp;
1382 *--cbpp = cbp->c_link[0];
1383 ep->e_off = cbp->c_voff[0];
1384 ep->e_frameindex = 0;
1385 ep->e_fval.s = cbp->c_linkv[0].s;
1386 ep->e_framecnt = cbp->c_framecnt[0];
1387 ep->e_emask = cbp->c_emask[0];
1388
1389 /* now update the emask info */
1390 s = 0;
1391 for (i = 2, ep += 2; i < nframes; i++, ep++) {
1392 cbp = ep->e_combo;
1393 nep = &einfo[ep->e_frameindex];
1394 nep->e_framecnt = cbp->c_framecnt[0];
1395 nep->e_emask = cbp->c_emask[0];
1396
1397 if ((cbp->c_flags & C_LOOP) != 0) {
1398 s++;
1399 /*
1400 * Account for the fact that this frame connects
1401 * to a previous one (thus forming a loop).
1402 */
1403 nep = &einfo[cbp->c_dir];
1404 if (--nep->e_framecnt != 0)
1405 nep->e_emask &= ~(1 << cbp->c_voff[0]);
1406 else
1407 nep->e_emask = 0;
1408 }
1409 }
1410
1411 /*
1412 * We only need to update the emask values of "complete" loops
1413 * to include the intersection spots.
1414 */
1415 if (s != 0 && ocbp->c_combo.c.a == 2) {
1416 /* process loops from the top down */
1417 ep = &einfo[nframes];
1418 do {
1419 ep--;
1420 cbp = ep->e_combo;
1421 if ((cbp->c_flags & C_LOOP) == 0)
1422 continue;
1423
1424 /*
1425 * Update the emask values to include the
1426 * intersection spots.
1427 */
1428 nep = &einfo[cbp->c_dir];
1429 nep->e_framecnt = 1;
1430 nep->e_emask = 1 << cbp->c_voff[0];
1431 ep->e_framecnt = 1;
1432 ep->e_emask = 1 << ep->e_off;
1433 ep = &einfo[ep->e_frameindex];
1434 do {
1435 ep->e_framecnt = 1;
1436 ep->e_emask = 1 << ep->e_off;
1437 ep = &einfo[ep->e_frameindex];
1438 } while (ep > nep);
1439 } while (ep != einfo);
1440 }
1441
1442 /* mark all the frames with the completion spots */
1443 for (i = 0, ep = einfo, cbpp = ecombo; i < nframes; i++, ep++, cbpp++) {
1444 m = ep->e_emask;
1445 cbp = *cbpp;
1446 sp = &board[cbp->c_vertex];
1447 d = dd[s = cbp->c_dir];
1448 cmask = CFLAG << s;
1449 omask = (IFLAG | CFLAG) << s;
1450 s = ep->e_fval.c.b != 0 ? 6 : 5;
1451 /* LINTED 117: bitwise '>>' on signed value possibly nonportable */
1452 for (; --s >= 0; sp += d, m >>= 1)
1453 sp->s_flags |= (m & 1) != 0 ? omask : cmask;
1454 }
1455 }
1456
1457 void
1458 clearcombo(struct combostr *cbp, int open)
1459 {
1460 struct spotstr *sp;
1461 struct combostr *tcbp;
1462 int d, n, mask;
1463
1464 for (; (tcbp = cbp->c_link[1]) != NULL; cbp = cbp->c_link[0]) {
1465 clearcombo(tcbp, cbp->c_flags & C_OPEN_1);
1466 open = cbp->c_flags & C_OPEN_0;
1467 }
1468 sp = &board[cbp->c_vertex];
1469 d = dd[n = cbp->c_dir];
1470 mask = ~((IFLAG | CFLAG) << n);
1471 n = open != 0 ? 6 : 5;
1472 for (; --n >= 0; sp += d)
1473 sp->s_flags &= mask;
1474 }
1475 #endif /* DEBUG */
1476