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