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