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