makemove.c revision 1.20
1/* $NetBSD: makemove.c,v 1.20 2022/05/21 16:39:14 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.20 2022/05/21 16:39:14 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[movenum - 1] = mv; 82 if (++movenum == BSZ * BSZ) 83 return TIE; 84 85 /* compute new frame values */ 86 sp->s_wval = 0; 87 osp = sp; 88 for (int r = 4; --r >= 0; ) { /* for each direction */ 89 d = dd[r]; 90 fsp = osp; 91 bmask = BFLAG << r; 92 for (int f = 5; --f >= 0; fsp -= d) { /* for each frame */ 93 if (fsp->s_occ == BORDER) 94 goto nextr; 95 if ((fsp->s_flags & bmask) != 0) 96 continue; 97 98 /* remove this frame from the sorted list of frames */ 99 cbp = fsp->s_frame[r]; 100 if (cbp->c_next != NULL) { 101 if (sortframes[BLACK] == cbp) 102 sortframes[BLACK] = cbp->c_next; 103 if (sortframes[WHITE] == cbp) 104 sortframes[WHITE] = cbp->c_next; 105 cbp->c_next->c_prev = cbp->c_prev; 106 cbp->c_prev->c_next = cbp->c_next; 107 } 108 109 /* compute old weight value for this frame */ 110 cp = &fsp->s_fval[BLACK][r]; 111 if (cp->s <= 0x500) 112 val = weight[5 - cp->cv_force - cp->cv_win]; 113 else 114 val = 0; 115 cp = &fsp->s_fval[WHITE][r]; 116 if (cp->s <= 0x500) 117 val += weight[5 - cp->cv_force - cp->cv_win]; 118 119 /* compute new combo value for this frame */ 120 sp = fsp; 121 space = sp->s_occ == EMPTY; 122 n = 0; 123 for (int i = 5; --i >= 0; sp += d) { /* for each spot */ 124 if (sp->s_occ == us) 125 n++; 126 else if (sp->s_occ == EMPTY) 127 sp->s_wval -= val; 128 else { 129 /* this frame is now blocked, adjust values */ 130 fsp->s_flags |= bmask; 131 fsp->s_fval[BLACK][r].s = 0x600; 132 fsp->s_fval[WHITE][r].s = 0x600; 133 while (--i >= 0) { 134 sp += d; 135 if (sp->s_occ == EMPTY) 136 sp->s_wval -= val; 137 } 138 goto nextf; 139 } 140 } 141 142 /* check for game over */ 143 if (n == 5) 144 return(WIN); 145 146 /* compute new value & combo number for this frame & color */ 147 fsp->s_fval[us != BLACK ? BLACK : WHITE][r].s = 0x600; 148 cp = &fsp->s_fval[us][r]; 149 /* both ends open? */ 150 if (space && sp->s_occ == EMPTY) { 151 cp->cv_force = 4 - n; 152 cp->cv_win = 1; 153 } else { 154 cp->cv_force = 5 - n; 155 cp->cv_win = 0; 156 } 157 val = weight[n]; 158 sp = fsp; 159 for (int i = 5; --i >= 0; sp += d) /* for each spot */ 160 if (sp->s_occ == EMPTY) 161 sp->s_wval += val; 162 163 /* add this frame to the sorted list of frames by combo value */ 164 cbp1 = sortframes[us]; 165 if (cbp1 == NULL) 166 sortframes[us] = cbp->c_next = cbp->c_prev = cbp; 167 else { 168 cp1 = &board[cbp1->c_vertex].s_fval[us][cbp1->c_dir]; 169 if (cp->s <= cp1->s) { 170 /* insert at the head of the list */ 171 sortframes[us] = cbp; 172 } else { 173 do { 174 cbp1 = cbp1->c_next; 175 cp1 = &board[cbp1->c_vertex].s_fval[us][cbp1->c_dir]; 176 if (cp->s <= cp1->s) 177 break; 178 } while (cbp1 != sortframes[us]); 179 } 180 cbp->c_next = cbp1; 181 cbp->c_prev = cbp1->c_prev; 182 cbp1->c_prev->c_next = cbp; 183 cbp1->c_prev = cbp; 184 } 185 186 nextf: 187 ; 188 } 189 190 /* both ends open? */ 191 if (fsp->s_occ == EMPTY) { 192 cp = &fsp->s_fval[BLACK][r]; 193 if (cp->cv_win != 0) { 194 cp->cv_force++; 195 cp->cv_win = 0; 196 } 197 cp = &fsp->s_fval[WHITE][r]; 198 if (cp->cv_win != 0) { 199 cp->cv_force++; 200 cp->cv_win = 0; 201 } 202 } 203 204 nextr: 205 ; 206 } 207 208 update_overlap(osp); 209 210 return MOVEOK; 211} 212 213/* 214 * fix up the overlap array due to updating spot osp. 215 */ 216static void 217update_overlap(struct spotstr *osp) 218{ 219 struct spotstr *sp, *sp1, *sp2; 220 int d, d1, n; 221 int a, b, bmask, bmask1; 222 struct spotstr *esp; 223 u_char *str; 224 225 esp = NULL; 226 for (int r = 4; --r >= 0; ) { /* for each direction */ 227 d = dd[r]; 228 sp1 = osp; 229 bmask = BFLAG << r; 230 for (int f = 0; f < 6; f++, sp1 -= d) { /* for each frame */ 231 if (sp1->s_occ == BORDER) 232 break; 233 if ((sp1->s_flags & bmask) != 0) 234 continue; 235 /* 236 * Update all other frames that intersect the current one 237 * to indicate whether they still overlap or not. 238 * Since F1 overlap F2 == F2 overlap F1, we only need to 239 * do the rows 0 <= r1 <= r. The r1 == r case is special 240 * since the two frames can overlap at more than one point. 241 */ 242 str = &overlap[(a = (int)(sp1->s_frame[r] - frames)) * FAREA]; 243 sp2 = sp1 - d; 244 for (int i = f + 1; i < 6; i++, sp2 -= d) { 245 if (sp2->s_occ == BORDER) 246 break; 247 if ((sp2->s_flags & bmask) != 0) 248 continue; 249 /* 250 * count the number of empty spots to see if there is 251 * still an overlap. 252 */ 253 n = 0; 254 sp = sp1; 255 for (b = i - f; b < 5; b++, sp += d) { 256 if (sp->s_occ == EMPTY) { 257 esp = sp; /* save the intersection point */ 258 n++; 259 } 260 } 261 b = (int)(sp2->s_frame[r] - frames); 262 if (n == 0) { 263 if (sp->s_occ == EMPTY) { 264 str[b] &= 0xA; 265 overlap[b * FAREA + a] &= 0xC; 266 intersect[a * FAREA + b] = n = (int)(sp - board); 267 intersect[b * FAREA + a] = n; 268 } else { 269 str[b] = 0; 270 overlap[b * FAREA + a] = 0; 271 } 272 } else if (n == 1) { 273 if (sp->s_occ == EMPTY) { 274 str[b] &= 0xAF; 275 overlap[b * FAREA + a] &= 0xCF; 276 } else { 277 str[b] &= 0xF; 278 overlap[b * FAREA + a] &= 0xF; 279 } 280 intersect[a * FAREA + b] = n = (int)(esp - board); 281 intersect[b * FAREA + a] = n; 282 } 283 /* else no change, still multiple overlap */ 284 } 285 286 /* the other directions can only intersect at spot osp */ 287 for (int r1 = r; --r1 >= 0; ) { 288 d1 = dd[r1]; 289 bmask1 = BFLAG << r1; 290 sp = osp; 291 for (int i = 6; --i >= 0; sp -= d1) { /* for each spot */ 292 if (sp->s_occ == BORDER) 293 break; 294 if ((sp->s_flags & bmask1) != 0) 295 continue; 296 b = (int)(sp->s_frame[r1] - frames); 297 str[b] = 0; 298 overlap[b * FAREA + a] = 0; 299 } 300 } 301 } 302 } 303} 304