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