| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: makemove.c,v 1.27 2022/05/28 05:14:34 rillig Exp $ */ | | 1 | /* $NetBSD: makemove.c,v 1.28 2022/05/28 05:44:41 rillig Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1994 | | 4 | * Copyright (c) 1994 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to Berkeley by | | 7 | * This code is derived from software contributed to Berkeley by |
8 | * Ralph Campbell. | | 8 | * Ralph Campbell. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -24,27 +24,27 @@ | | | @@ -24,27 +24,27 @@ |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 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 | | 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 | | 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 | | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
32 | * SUCH DAMAGE. | | 32 | * SUCH DAMAGE. |
33 | */ | | 33 | */ |
34 | | | 34 | |
35 | #include <sys/cdefs.h> | | 35 | #include <sys/cdefs.h> |
36 | /* @(#)makemove.c 8.2 (Berkeley) 5/3/95 */ | | 36 | /* @(#)makemove.c 8.2 (Berkeley) 5/3/95 */ |
37 | __RCSID("$NetBSD: makemove.c,v 1.27 2022/05/28 05:14:34 rillig Exp $"); | | 37 | __RCSID("$NetBSD: makemove.c,v 1.28 2022/05/28 05:44:41 rillig Exp $"); |
38 | | | 38 | |
39 | #include "gomoku.h" | | 39 | #include "gomoku.h" |
40 | | | 40 | |
41 | /* direction deltas */ | | 41 | /* direction deltas */ |
42 | const int dd[4] = { | | 42 | const int dd[4] = { |
43 | 1, /* right */ | | 43 | 1, /* right */ |
44 | -(BSZ + 1) + 1, /* down + right */ | | 44 | -(BSZ + 1) + 1, /* down + right */ |
45 | -(BSZ + 1), /* down */ | | 45 | -(BSZ + 1), /* down */ |
46 | -(BSZ + 1) - 1 /* down + left */ | | 46 | -(BSZ + 1) - 1 /* down + left */ |
47 | }; | | 47 | }; |
48 | | | 48 | |
49 | static const int weight[5] = { 0, 1, 7, 22, 100 }; | | 49 | static const int weight[5] = { 0, 1, 7, 22, 100 }; |
50 | | | 50 | |
| @@ -67,30 +67,29 @@ makemove(int us, int mv) | | | @@ -67,30 +67,29 @@ makemove(int us, int mv) |
67 | return RESIGN; | | 67 | return RESIGN; |
68 | | | 68 | |
69 | /* check for illegal move */ | | 69 | /* check for illegal move */ |
70 | struct spotstr *sp = &board[mv]; | | 70 | struct spotstr *sp = &board[mv]; |
71 | if (sp->s_occ != EMPTY) | | 71 | if (sp->s_occ != EMPTY) |
72 | return ILLEGAL; | | 72 | return ILLEGAL; |
73 | | | 73 | |
74 | /* make move */ | | 74 | /* make move */ |
75 | sp->s_occ = us; | | 75 | sp->s_occ = us; |
76 | movelog[nmoves++] = mv; | | 76 | movelog[nmoves++] = mv; |
77 | | | 77 | |
78 | /* compute new frame values */ | | 78 | /* compute new frame values */ |
79 | sp->s_wval = 0; | | 79 | sp->s_wval = 0; |
80 | struct spotstr *osp = sp; | | | |
81 | for (int r = 4; --r >= 0; ) { /* for each direction */ | | 80 | for (int r = 4; --r >= 0; ) { /* for each direction */ |
82 | int d = dd[r]; | | 81 | int d = dd[r]; |
83 | struct spotstr *fsp = osp; | | 82 | struct spotstr *fsp = &board[mv]; |
84 | int bmask = BFLAG << r; | | 83 | int bmask = BFLAG << r; |
85 | | | 84 | |
86 | for (int f = 5; --f >= 0; fsp -= d) { /* for each frame */ | | 85 | for (int f = 5; --f >= 0; fsp -= d) { /* for each frame */ |
87 | if (fsp->s_occ == BORDER) | | 86 | if (fsp->s_occ == BORDER) |
88 | goto nextr; | | 87 | goto nextr; |
89 | if ((fsp->s_flags & bmask) != 0) | | 88 | if ((fsp->s_flags & bmask) != 0) |
90 | continue; | | 89 | continue; |
91 | | | 90 | |
92 | /* remove this frame from the sorted list of frames */ | | 91 | /* remove this frame from the sorted list of frames */ |
93 | struct combostr *cbp = fsp->s_frame[r]; | | 92 | struct combostr *cbp = fsp->s_frame[r]; |
94 | if (cbp->c_next != NULL) { | | 93 | if (cbp->c_next != NULL) { |
95 | if (sortframes[BLACK] == cbp) | | 94 | if (sortframes[BLACK] == cbp) |
96 | sortframes[BLACK] = cbp->c_next; | | 95 | sortframes[BLACK] = cbp->c_next; |
| @@ -188,107 +187,117 @@ makemove(int us, int mv) | | | @@ -188,107 +187,117 @@ makemove(int us, int mv) |
188 | cp->cv_win = 0; | | 187 | cp->cv_win = 0; |
189 | } | | 188 | } |
190 | cp = &fsp->s_fval[WHITE][r]; | | 189 | cp = &fsp->s_fval[WHITE][r]; |
191 | if (cp->cv_win != 0) { | | 190 | if (cp->cv_win != 0) { |
192 | cp->cv_force++; | | 191 | cp->cv_force++; |
193 | cp->cv_win = 0; | | 192 | cp->cv_win = 0; |
194 | } | | 193 | } |
195 | } | | 194 | } |
196 | | | 195 | |
197 | nextr: | | 196 | nextr: |
198 | ; | | 197 | ; |
199 | } | | 198 | } |
200 | | | 199 | |
201 | update_overlap(osp); | | 200 | update_overlap(&board[mv]); |
202 | | | 201 | |
203 | /* | | 202 | /* |
204 | * TODO: Declare a tie as soon as all frames are blocked. This is | | 203 | * TODO: Declare a tie as soon as all frames are blocked. This is |
205 | * usually much earlier than when the whole board is filled. | | 204 | * usually much earlier than when the whole board is filled. |
206 | */ | | 205 | */ |
207 | if (nmoves == BSZ * BSZ) | | 206 | if (nmoves == BSZ * BSZ) |
208 | return TIE; | | 207 | return TIE; |
209 | | | 208 | |
210 | return MOVEOK; | | 209 | return MOVEOK; |
211 | } | | 210 | } |
212 | | | 211 | |
| | | 212 | static void |
| | | 213 | update_overlap_same_direction(const struct spotstr *sp1, |
| | | 214 | const struct spotstr *sp2, |
| | | 215 | int a, int d, int i_minus_f, int r) |
| | | 216 | { |
| | | 217 | /* |
| | | 218 | * count the number of empty spots to see if there is |
| | | 219 | * still an overlap. |
| | | 220 | */ |
| | | 221 | int n = 0; |
| | | 222 | const struct spotstr *sp = sp1; |
| | | 223 | const struct spotstr *esp = NULL; |
| | | 224 | for (int b = i_minus_f; b < 5; b++, sp += d) { |
| | | 225 | if (sp->s_occ == EMPTY) { |
| | | 226 | esp = sp; /* save the intersection point */ |
| | | 227 | n++; |
| | | 228 | } |
| | | 229 | } |
| | | 230 | |
| | | 231 | int b = (int)(sp2->s_frame[r] - frames); |
| | | 232 | if (n == 0) { |
| | | 233 | if (sp->s_occ == EMPTY) { |
| | | 234 | overlap[a * FAREA + b] &= 0xA; |
| | | 235 | overlap[b * FAREA + a] &= 0xC; |
| | | 236 | intersect[a * FAREA + b] = (short)(sp - board); |
| | | 237 | intersect[b * FAREA + a] = (short)(sp - board); |
| | | 238 | } else { |
| | | 239 | overlap[a * FAREA + b] = 0; |
| | | 240 | overlap[b * FAREA + a] = 0; |
| | | 241 | } |
| | | 242 | } else if (n == 1) { |
| | | 243 | if (sp->s_occ == EMPTY) { |
| | | 244 | overlap[a * FAREA + b] &= 0xAF; |
| | | 245 | overlap[b * FAREA + a] &= 0xCF; |
| | | 246 | } else { |
| | | 247 | overlap[a * FAREA + b] &= 0xF; |
| | | 248 | overlap[b * FAREA + a] &= 0xF; |
| | | 249 | } |
| | | 250 | intersect[a * FAREA + b] = (short)(esp - board); |
| | | 251 | intersect[b * FAREA + a] = (short)(esp - board); |
| | | 252 | } |
| | | 253 | /* else no change, still multiple overlap */ |
| | | 254 | } |
| | | 255 | |
213 | /* | | 256 | /* |
214 | * fix up the overlap array due to updating spot osp. | | 257 | * fix up the overlap array according to the changed 'osp'. |
215 | */ | | 258 | */ |
216 | static void | | 259 | static void |
217 | update_overlap(struct spotstr *osp) | | 260 | update_overlap(struct spotstr *osp) |
218 | { | | 261 | { |
219 | | | 262 | |
220 | for (int r = 4; --r >= 0; ) { /* for each direction */ | | 263 | for (int r = 4; --r >= 0; ) { /* for each direction */ |
221 | int d = dd[r]; | | 264 | int d = dd[r]; |
222 | struct spotstr *sp1 = osp; | | 265 | struct spotstr *sp1 = osp; |
223 | | | 266 | |
224 | for (int f = 0; f < 6; f++, sp1 -= d) { /* for each frame */ | | 267 | /* for each frame that contains 'osp' */ |
| | | 268 | for (int f = 0; f < 6; f++, sp1 -= d) { |
225 | if (sp1->s_occ == BORDER) | | 269 | if (sp1->s_occ == BORDER) |
226 | break; | | 270 | break; |
227 | if ((sp1->s_flags & BFLAG << r) != 0) | | 271 | if ((sp1->s_flags & BFLAG << r) != 0) |
228 | continue; | | 272 | continue; |
| | | 273 | |
229 | /* | | 274 | /* |
230 | * Update all other frames that intersect the current one | | 275 | * Update all other frames that intersect the current one |
231 | * to indicate whether they still overlap or not. | | 276 | * to indicate whether they still overlap or not. |
232 | * Since F1 overlap F2 == F2 overlap F1, we only need to | | 277 | * Since F1 overlap F2 == F2 overlap F1, we only need to |
233 | * do the rows 0 <= r1 <= r. The r1 == r case is special | | 278 | * do the rows 0 <= r1 <= r. The r1 == r case is special |
234 | * since the two frames can overlap at more than one point. | | 279 | * since the two frames can overlap at more than one point. |
235 | */ | | 280 | */ |
236 | int a = (int)(sp1->s_frame[r] - frames); | | 281 | int a = (int)(sp1->s_frame[r] - frames); |
237 | struct spotstr *sp2 = sp1 - d; | | 282 | struct spotstr *sp2 = sp1 - d; |
238 | | | 283 | |
239 | for (int i = f + 1; i < 6; i++, sp2 -= d) { | | 284 | for (int i = f + 1; i < 6; i++, sp2 -= d) { |
240 | if (sp2->s_occ == BORDER) | | 285 | if (sp2->s_occ == BORDER) |
241 | break; | | 286 | break; |
242 | if ((sp2->s_flags & BFLAG << r) != 0) | | 287 | if ((sp2->s_flags & BFLAG << r) != 0) |
243 | continue; | | 288 | continue; |
244 | | | 289 | |
245 | /* | | 290 | update_overlap_same_direction(sp1, sp2, a, d, i - f, r); |
246 | * count the number of empty spots to see if there is | | | |
247 | * still an overlap. | | | |
248 | */ | | | |
249 | int n = 0; | | | |
250 | struct spotstr *sp = sp1; | | | |
251 | struct spotstr *esp = NULL; | | | |
252 | for (int b = i - f; b < 5; b++, sp += d) { | | | |
253 | if (sp->s_occ == EMPTY) { | | | |
254 | esp = sp; /* save the intersection point */ | | | |
255 | n++; | | | |
256 | } | | | |
257 | } | | | |
258 | | | | |
259 | int b = (int)(sp2->s_frame[r] - frames); | | | |
260 | if (n == 0) { | | | |
261 | if (sp->s_occ == EMPTY) { | | | |
262 | overlap[a * FAREA + b] &= 0xA; | | | |
263 | overlap[b * FAREA + a] &= 0xC; | | | |
264 | intersect[a * FAREA + b] = (short)(sp - board); | | | |
265 | intersect[b * FAREA + a] = (short)(sp - board); | | | |
266 | } else { | | | |
267 | overlap[a * FAREA + b] = 0; | | | |
268 | overlap[b * FAREA + a] = 0; | | | |
269 | } | | | |
270 | } else if (n == 1) { | | | |
271 | if (sp->s_occ == EMPTY) { | | | |
272 | overlap[a * FAREA + b] &= 0xAF; | | | |
273 | overlap[b * FAREA + a] &= 0xCF; | | | |
274 | } else { | | | |
275 | overlap[a * FAREA + b] &= 0xF; | | | |
276 | overlap[b * FAREA + a] &= 0xF; | | | |
277 | } | | | |
278 | intersect[a * FAREA + b] = (short)(esp - board); | | | |
279 | intersect[b * FAREA + a] = (short)(esp - board); | | | |
280 | } | | | |
281 | /* else no change, still multiple overlap */ | | | |
282 | } | | 291 | } |
283 | | | 292 | |
284 | /* the other directions can only intersect at spot osp */ | | 293 | /* the other directions can only intersect at spot osp */ |
285 | for (int r1 = r; --r1 >= 0; ) { | | 294 | for (int r1 = r; --r1 >= 0; ) { |
286 | int d1 = dd[r1]; | | 295 | int d1 = dd[r1]; |
287 | struct spotstr *sp = osp; | | 296 | struct spotstr *sp = osp; |
288 | for (int i = 6; --i >= 0; sp -= d1) { /* for each spot */ | | 297 | for (int i = 6; --i >= 0; sp -= d1) { /* for each spot */ |
289 | if (sp->s_occ == BORDER) | | 298 | if (sp->s_occ == BORDER) |
290 | break; | | 299 | break; |
291 | if ((sp->s_flags & BFLAG << r1) != 0) | | 300 | if ((sp->s_flags & BFLAG << r1) != 0) |
292 | continue; | | 301 | continue; |
293 | int b = (int)(sp->s_frame[r1] - frames); | | 302 | int b = (int)(sp->s_frame[r1] - frames); |
294 | overlap[a * FAREA + b] = 0; | | 303 | overlap[a * FAREA + b] = 0; |