makemove.c revision 1.8
1/*	$NetBSD: makemove.c,v 1.8 2006/05/11 00:17:07 mrg 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#ifndef lint
37#if 0
38static char sccsid[] = "@(#)makemove.c	8.2 (Berkeley) 5/3/95";
39#else
40__RCSID("$NetBSD: makemove.c,v 1.8 2006/05/11 00:17:07 mrg Exp $");
41#endif
42#endif /* not lint */
43
44#include "gomoku.h"
45
46		/* direction deltas */
47const int     dd[4] = {
48	MRIGHT, MRIGHT+MDOWN, MDOWN, MDOWN+MLEFT
49};
50
51const int	weight[5] = { 0, 1, 7, 22, 100 };
52
53/*
54 * Return values:
55 *	MOVEOK	everything is OK.
56 *	RESIGN	Player resigned.
57 *	ILLEGAL	Illegal move.
58 *	WIN	The winning move was just played.
59 *	TIE	The game is a tie.
60 */
61int
62makemove(us, mv)
63	int us, mv;
64{
65	struct spotstr *sp, *fsp;
66	union comboval *cp;
67	struct spotstr *osp;
68	struct combostr *cbp, *cbp1;
69	union comboval *cp1;
70	int i, f, r, d, n;
71	int space, val, bmask;
72
73	/* check for end of game */
74	if (mv == RESIGN)
75		return(RESIGN);
76
77	/* check for illegal move */
78	sp = &board[mv];
79	if (sp->s_occ != EMPTY)
80		return(ILLEGAL);
81
82	/* make move */
83	sp->s_occ = us;
84	movelog[movenum - 1] = mv;
85	if (++movenum == BSZ * BSZ)
86		return(TIE);
87
88	/* compute new frame values */
89	sp->s_wval = 0;
90	osp = sp;
91	for (r = 4; --r >= 0; ) {			/* for each direction */
92	    d = dd[r];
93	    fsp = osp;
94	    bmask = BFLAG << r;
95	    for (f = 5; --f >= 0; fsp -= d) {		/* for each frame */
96		if (fsp->s_occ == BORDER)
97		    goto nextr;
98		if (fsp->s_flg & bmask)
99		    continue;
100
101		/* remove this frame from the sorted list of frames */
102		cbp = fsp->s_frame[r];
103		if (cbp->c_next) {
104			if (sortframes[BLACK] == cbp)
105			    sortframes[BLACK] = cbp->c_next;
106			if (sortframes[WHITE] == cbp)
107			    sortframes[WHITE] = cbp->c_next;
108			cbp->c_next->c_prev = cbp->c_prev;
109			cbp->c_prev->c_next = cbp->c_next;
110		}
111
112		/* compute old weight value for this frame */
113		cp = &fsp->s_fval[BLACK][r];
114		if (cp->s <= 0x500)
115		    val = weight[5 - cp->c.a - cp->c.b];
116		else
117		    val = 0;
118		cp = &fsp->s_fval[WHITE][r];
119		if (cp->s <= 0x500)
120		    val += weight[5 - cp->c.a - cp->c.b];
121
122		/* compute new combo value for this frame */
123		sp = fsp;
124		space = sp->s_occ == EMPTY;
125		n = 0;
126		for (i = 5; --i >= 0; sp += d) {	/* for each spot */
127		    if (sp->s_occ == us)
128			n++;
129		    else if (sp->s_occ == EMPTY)
130			sp->s_wval -= val;
131		    else {
132			/* this frame is now blocked, adjust values */
133			fsp->s_flg |= bmask;
134			fsp->s_fval[BLACK][r].s = MAXCOMBO;
135			fsp->s_fval[WHITE][r].s = MAXCOMBO;
136			while (--i >= 0) {
137			    sp += d;
138			    if (sp->s_occ == EMPTY)
139				sp->s_wval -= val;
140			}
141			goto nextf;
142		    }
143		}
144
145		/* check for game over */
146		if (n == 5)
147		    return(WIN);
148
149		/* compute new value & combo number for this frame & color */
150		fsp->s_fval[!us][r].s = MAXCOMBO;
151		cp = &fsp->s_fval[us][r];
152		/* both ends open? */
153		if (space && sp->s_occ == EMPTY) {
154		    cp->c.a = 4 - n;
155		    cp->c.b = 1;
156		} else {
157		    cp->c.a = 5 - n;
158		    cp->c.b = 0;
159		}
160		val = weight[n];
161		sp = fsp;
162		for (i = 5; --i >= 0; sp += d)		/* for each spot */
163		    if (sp->s_occ == EMPTY)
164			sp->s_wval += val;
165
166		/* add this frame to the sorted list of frames by combo value */
167		cbp1 = sortframes[us];
168		if (!cbp1)
169		    sortframes[us] = cbp->c_next = cbp->c_prev = cbp;
170		else {
171		    cp1 = &board[cbp1->c_vertex].s_fval[us][cbp1->c_dir];
172		    if (cp->s <= cp1->s) {
173			/* insert at the head of the list */
174			sortframes[us] = cbp;
175		    } else {
176			do {
177			    cbp1 = cbp1->c_next;
178			    cp1 = &board[cbp1->c_vertex].s_fval[us][cbp1->c_dir];
179			    if (cp->s <= cp1->s)
180				break;
181			} while (cbp1 != sortframes[us]);
182		    }
183		    cbp->c_next = cbp1;
184		    cbp->c_prev = cbp1->c_prev;
185		    cbp1->c_prev->c_next = cbp;
186		    cbp1->c_prev = cbp;
187		}
188
189	    nextf:
190		;
191	    }
192
193	    /* both ends open? */
194	    if (fsp->s_occ == EMPTY) {
195		cp = &fsp->s_fval[BLACK][r];
196		if (cp->c.b) {
197		    cp->c.a += 1;
198		    cp->c.b = 0;
199		}
200		cp = &fsp->s_fval[WHITE][r];
201		if (cp->c.b) {
202		    cp->c.a += 1;
203		    cp->c.b = 0;
204		}
205	    }
206
207	nextr:
208	    ;
209	}
210
211	update_overlap(osp);
212
213	return(MOVEOK);
214}
215
216/*
217 * fix up the overlap array due to updating spot osp.
218 */
219void
220update_overlap(osp)
221	struct spotstr *osp;
222{
223	struct spotstr *sp, *sp1, *sp2;
224	int i, f, r, r1, d, d1, n;
225	int a, b, bmask, bmask1;
226	struct spotstr *esp;
227	u_char *str;
228
229	esp = NULL;
230	for (r = 4; --r >= 0; ) {			/* for each direction */
231	    d = dd[r];
232	    sp1 = osp;
233	    bmask = BFLAG << r;
234	    for (f = 0; f < 6; f++, sp1 -= d) {		/* for each frame */
235		if (sp1->s_occ == BORDER)
236		    break;
237		if (sp1->s_flg & bmask)
238		    continue;
239		/*
240		 * Update all other frames that intersect the current one
241		 * to indicate whether they still overlap or not.
242		 * Since F1 overlap F2 == F2 overlap F1, we only need to
243		 * do the rows 0 <= r1 <= r. The r1 == r case is special
244		 * since the two frames can overlap at more than one point.
245		 */
246		str = &overlap[(a = sp1->s_frame[r] - frames) * FAREA];
247		sp2 = sp1 - d;
248		for (i = f + 1; i < 6; i++, sp2 -= d) {
249		    if (sp2->s_occ == BORDER)
250			break;
251		    if (sp2->s_flg & bmask)
252			continue;
253		    /*
254		     * count the number of empty spots to see if there is
255		     * still an overlap.
256		     */
257		    n = 0;
258		    sp = sp1;
259		    for (b = i - f; b < 5; b++, sp += d) {
260			if (sp->s_occ == EMPTY) {
261			    esp = sp;	/* save the intersection point */
262			    n++;
263			}
264		    }
265		    b = sp2->s_frame[r] - frames;
266		    if (n == 0) {
267			if (sp->s_occ == EMPTY) {
268			    str[b] &= 0xA;
269			    overlap[b * FAREA + a] &= 0xC;
270			    intersect[a * FAREA + b] = n = sp - board;
271			    intersect[b * FAREA + a] = n;
272			} else {
273			    str[b] = 0;
274			    overlap[b * FAREA + a] = 0;
275			}
276		    } else if (n == 1) {
277			if (sp->s_occ == EMPTY) {
278			    str[b] &= 0xAF;
279			    overlap[b * FAREA + a] &= 0xCF;
280			} else {
281			    str[b] &= 0xF;
282			    overlap[b * FAREA + a] &= 0xF;
283			}
284			intersect[a * FAREA + b] = n = esp - board;
285			intersect[b * FAREA + a] = n;
286		    }
287		    /* else no change, still multiple overlap */
288		}
289
290		/* the other directions can only intersect at spot osp */
291		for (r1 = r; --r1 >= 0; ) {
292		    d1 = dd[r1];
293		    bmask1 = BFLAG << r1;
294		    sp = osp;
295		    for (i = 6; --i >= 0; sp -= d1) {	/* for each spot */
296			if (sp->s_occ == BORDER)
297			    break;
298			if (sp->s_flg & bmask1)
299			    continue;
300			b = sp->s_frame[r1] - frames;
301			str[b] = 0;
302			overlap[b * FAREA + a] = 0;
303		    }
304		}
305	    }
306	}
307}
308