makemove.c revision 1.22
1/* $NetBSD: makemove.c,v 1.22 2022/05/27 20:35:58 rillig Exp $ */ 2 3/* 4 * Copyright (c) 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Ralph Campbell. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35#include <sys/cdefs.h> 36/* @(#)makemove.c 8.2 (Berkeley) 5/3/95 */ 37__RCSID("$NetBSD: makemove.c,v 1.22 2022/05/27 20:35:58 rillig Exp $"); 38 39#include "gomoku.h" 40 41 /* direction deltas */ 42const int dd[4] = { 43 MRIGHT, MRIGHT+MDOWN, MDOWN, MDOWN+MLEFT 44}; 45 46static const int weight[5] = { 0, 1, 7, 22, 100 }; 47 48static void update_overlap(struct spotstr *); 49 50/* 51 * Return values: 52 * MOVEOK everything is OK. 53 * RESIGN Player resigned. 54 * ILLEGAL Illegal move. 55 * WIN The winning move was just played. 56 * TIE The game is a tie. 57 */ 58int 59makemove(int us, int mv) 60{ 61 struct spotstr *sp, *fsp; 62 union comboval *cp; 63 struct spotstr *osp; 64 struct combostr *cbp, *cbp1; 65 union comboval *cp1; 66 int d, n; 67 int val, bmask; 68 bool space; 69 70 /* check for end of game */ 71 if (mv == RESIGN) 72 return RESIGN; 73 74 /* check for illegal move */ 75 sp = &board[mv]; 76 if (sp->s_occ != EMPTY) 77 return ILLEGAL; 78 79 /* make move */ 80 sp->s_occ = us; 81 movelog[nmoves++] = mv; 82 83 /* 84 * FIXME: The last spot on the board can still complete a frame. 85 * 86 * Example game: A1 B1 C1 D1 E1 F1 G1 H1 J1 K1 L1 M1 N1 O1 P1 Q1 R1 87 * S1 T1 A2 B2 C2 D2 E2 F2 G2 H2 J2 K2 L2 M2 N2 O2 P2 Q2 R2 S2 T2 A3 88 * B3 C3 D3 E3 F3 G3 H3 J3 K3 L3 M3 N3 O3 P3 Q3 R3 S3 T3 A4 B4 C4 D4 89 * E4 F4 G4 H4 J4 K4 L4 M4 N4 O4 P4 Q4 R4 S4 T4 B5 C5 D5 E5 F5 G5 H5 90 * J5 K5 L5 M5 N5 O5 P5 Q5 R5 S5 T5 B6 C6 D6 E6 F6 G6 H6 J6 K6 L6 M6 91 * N6 O6 P6 Q6 R6 S6 T6 B7 C7 D7 E7 F7 G7 H7 J7 K7 L7 M7 N7 O7 P7 Q7 92 * R7 S7 T7 A8 B8 C8 D8 E8 F8 G8 H8 J8 K8 L8 M8 N8 O8 P8 Q8 R8 S8 T8 93 * A9 B9 C9 D9 E9 F9 G9 H9 J9 K9 L9 M9 N9 O9 P9 Q9 R9 S9 T9 A10 B10 94 * C10 D10 E10 F10 G10 H10 J10 K10 L10 M10 N10 O10 P10 Q10 R10 S10 95 * T10 B11 C11 D11 E11 F11 G11 H11 J11 K11 L11 M11 N11 O11 P11 Q11 96 * R11 S11 T11 B12 C12 D12 E12 F12 G12 H12 J12 K12 L12 M12 N12 O12 97 * P12 Q12 R12 S12 T12 B13 C13 D13 E13 F13 G13 H13 J13 K13 L13 M13 98 * N13 O13 P13 Q13 R13 S13 T13 A14 B14 C14 D14 E14 F14 G14 H14 J14 99 * K14 L14 M14 N14 O14 P14 Q14 R14 S14 T14 A15 B15 C15 D15 E15 F15 100 * G15 H15 J15 K15 L15 M15 N15 O15 P15 Q15 R15 S15 T15 A16 B16 C16 101 * D16 E16 F16 G16 H16 J16 K16 L16 M16 N16 O16 P16 Q16 R16 S16 T16 102 * B17 C17 D17 E17 F17 G17 H17 J17 K17 L17 M17 N17 O17 P17 Q17 R17 103 * S17 T17 B18 C18 D18 E18 F18 G18 H18 J18 K18 L18 M18 N18 O18 P18 104 * Q18 R18 S18 T18 A11 A5 A12 A6 A13 A7 A18 A17 A19 B19 C19 D19 E19 105 * F19 G19 H19 J19 K19 L19 T19 M19 S19 N19 R19 O19 Q19 106 * 107 * Now P19 is the last remaining spot, and when Black plays there, 108 * the frame L19-P19 is complete. 109 */ 110 if (nmoves == BSZ * BSZ) 111 return TIE; 112 113 /* compute new frame values */ 114 sp->s_wval = 0; 115 osp = sp; 116 for (int r = 4; --r >= 0; ) { /* for each direction */ 117 d = dd[r]; 118 fsp = osp; 119 bmask = BFLAG << r; 120 for (int f = 5; --f >= 0; fsp -= d) { /* for each frame */ 121 if (fsp->s_occ == BORDER) 122 goto nextr; 123 if ((fsp->s_flags & bmask) != 0) 124 continue; 125 126 /* remove this frame from the sorted list of frames */ 127 cbp = fsp->s_frame[r]; 128 if (cbp->c_next != NULL) { 129 if (sortframes[BLACK] == cbp) 130 sortframes[BLACK] = cbp->c_next; 131 if (sortframes[WHITE] == cbp) 132 sortframes[WHITE] = cbp->c_next; 133 cbp->c_next->c_prev = cbp->c_prev; 134 cbp->c_prev->c_next = cbp->c_next; 135 } 136 137 /* compute old weight value for this frame */ 138 cp = &fsp->s_fval[BLACK][r]; 139 if (cp->s <= 0x500) 140 val = weight[5 - cp->cv_force - cp->cv_win]; 141 else 142 val = 0; 143 cp = &fsp->s_fval[WHITE][r]; 144 if (cp->s <= 0x500) 145 val += weight[5 - cp->cv_force - cp->cv_win]; 146 147 /* compute new combo value for this frame */ 148 sp = fsp; 149 space = sp->s_occ == EMPTY; 150 n = 0; 151 for (int i = 5; --i >= 0; sp += d) { /* for each spot */ 152 if (sp->s_occ == us) 153 n++; 154 else if (sp->s_occ == EMPTY) 155 sp->s_wval -= val; 156 else { 157 /* this frame is now blocked, adjust values */ 158 fsp->s_flags |= bmask; 159 fsp->s_fval[BLACK][r].s = 0x600; 160 fsp->s_fval[WHITE][r].s = 0x600; 161 while (--i >= 0) { 162 sp += d; 163 if (sp->s_occ == EMPTY) 164 sp->s_wval -= val; 165 } 166 goto nextf; 167 } 168 } 169 170 /* check for game over */ 171 if (n == 5) 172 return(WIN); 173 174 /* compute new value & combo number for this frame & color */ 175 fsp->s_fval[us != BLACK ? BLACK : WHITE][r].s = 0x600; 176 cp = &fsp->s_fval[us][r]; 177 /* both ends open? */ 178 if (space && sp->s_occ == EMPTY) { 179 cp->cv_force = 4 - n; 180 cp->cv_win = 1; 181 } else { 182 cp->cv_force = 5 - n; 183 cp->cv_win = 0; 184 } 185 val = weight[n]; 186 sp = fsp; 187 for (int i = 5; --i >= 0; sp += d) /* for each spot */ 188 if (sp->s_occ == EMPTY) 189 sp->s_wval += val; 190 191 /* add this frame to the sorted list of frames by combo value */ 192 cbp1 = sortframes[us]; 193 if (cbp1 == NULL) 194 sortframes[us] = cbp->c_next = cbp->c_prev = cbp; 195 else { 196 cp1 = &board[cbp1->c_vertex].s_fval[us][cbp1->c_dir]; 197 if (cp->s <= cp1->s) { 198 /* insert at the head of the list */ 199 sortframes[us] = cbp; 200 } else { 201 do { 202 cbp1 = cbp1->c_next; 203 cp1 = &board[cbp1->c_vertex].s_fval[us][cbp1->c_dir]; 204 if (cp->s <= cp1->s) 205 break; 206 } while (cbp1 != sortframes[us]); 207 } 208 cbp->c_next = cbp1; 209 cbp->c_prev = cbp1->c_prev; 210 cbp1->c_prev->c_next = cbp; 211 cbp1->c_prev = cbp; 212 } 213 214 nextf: 215 ; 216 } 217 218 /* both ends open? */ 219 if (fsp->s_occ == EMPTY) { 220 cp = &fsp->s_fval[BLACK][r]; 221 if (cp->cv_win != 0) { 222 cp->cv_force++; 223 cp->cv_win = 0; 224 } 225 cp = &fsp->s_fval[WHITE][r]; 226 if (cp->cv_win != 0) { 227 cp->cv_force++; 228 cp->cv_win = 0; 229 } 230 } 231 232 nextr: 233 ; 234 } 235 236 update_overlap(osp); 237 238 return MOVEOK; 239} 240 241/* 242 * fix up the overlap array due to updating spot osp. 243 */ 244static void 245update_overlap(struct spotstr *osp) 246{ 247 struct spotstr *sp, *sp1, *sp2; 248 int d, d1, n; 249 int a, b, bmask, bmask1; 250 struct spotstr *esp; 251 u_char *str; 252 253 esp = NULL; 254 for (int r = 4; --r >= 0; ) { /* for each direction */ 255 d = dd[r]; 256 sp1 = osp; 257 bmask = BFLAG << r; 258 for (int f = 0; f < 6; f++, sp1 -= d) { /* for each frame */ 259 if (sp1->s_occ == BORDER) 260 break; 261 if ((sp1->s_flags & bmask) != 0) 262 continue; 263 /* 264 * Update all other frames that intersect the current one 265 * to indicate whether they still overlap or not. 266 * Since F1 overlap F2 == F2 overlap F1, we only need to 267 * do the rows 0 <= r1 <= r. The r1 == r case is special 268 * since the two frames can overlap at more than one point. 269 */ 270 str = &overlap[(a = (int)(sp1->s_frame[r] - frames)) * FAREA]; 271 sp2 = sp1 - d; 272 for (int i = f + 1; i < 6; i++, sp2 -= d) { 273 if (sp2->s_occ == BORDER) 274 break; 275 if ((sp2->s_flags & bmask) != 0) 276 continue; 277 /* 278 * count the number of empty spots to see if there is 279 * still an overlap. 280 */ 281 n = 0; 282 sp = sp1; 283 for (b = i - f; b < 5; b++, sp += d) { 284 if (sp->s_occ == EMPTY) { 285 esp = sp; /* save the intersection point */ 286 n++; 287 } 288 } 289 b = (int)(sp2->s_frame[r] - frames); 290 if (n == 0) { 291 if (sp->s_occ == EMPTY) { 292 str[b] &= 0xA; 293 overlap[b * FAREA + a] &= 0xC; 294 intersect[a * FAREA + b] = n = (int)(sp - board); 295 intersect[b * FAREA + a] = n; 296 } else { 297 str[b] = 0; 298 overlap[b * FAREA + a] = 0; 299 } 300 } else if (n == 1) { 301 if (sp->s_occ == EMPTY) { 302 str[b] &= 0xAF; 303 overlap[b * FAREA + a] &= 0xCF; 304 } else { 305 str[b] &= 0xF; 306 overlap[b * FAREA + a] &= 0xF; 307 } 308 intersect[a * FAREA + b] = n = (int)(esp - board); 309 intersect[b * FAREA + a] = n; 310 } 311 /* else no change, still multiple overlap */ 312 } 313 314 /* the other directions can only intersect at spot osp */ 315 for (int r1 = r; --r1 >= 0; ) { 316 d1 = dd[r1]; 317 bmask1 = BFLAG << r1; 318 sp = osp; 319 for (int i = 6; --i >= 0; sp -= d1) { /* for each spot */ 320 if (sp->s_occ == BORDER) 321 break; 322 if ((sp->s_flags & bmask1) != 0) 323 continue; 324 b = (int)(sp->s_frame[r1] - frames); 325 str[b] = 0; 326 overlap[b * FAREA + a] = 0; 327 } 328 } 329 } 330 } 331} 332