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