/* $OpenBSD: makemove.c,v 1.7 2009/10/27 23:59:24 deraadt Exp $ */ /* * Copyright (c) 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "gomoku.h" /* direction deltas */ int dd[4] = { MRIGHT, MRIGHT+MDOWN, MDOWN, MDOWN+MLEFT }; int weight[5] = { 0, 1, 7, 22, 100 }; /* * Return values: * MOVEOK everything is OK. * RESIGN Player resigned. * ILLEGAL Illegal move. * WIN The winning move was just played. * TIE The game is a tie. */ int makemove(us, mv) int us, mv; { struct spotstr *sp, *fsp; union comboval *cp; struct spotstr *osp; struct combostr *cbp, *cbp1; union comboval *cp1; int i, f, r, d, n; int space, val, bmask; /* check for end of game */ if (mv == RESIGN) return(RESIGN); /* check for illegal move */ sp = &board[mv]; if (sp->s_occ != EMPTY) return(ILLEGAL); /* make move */ sp->s_occ = us; movelog[movenum - 1] = mv; if (++movenum == BSZ * BSZ) return(TIE); /* compute new frame values */ sp->s_wval = 0; osp = sp; for (r = 4; --r >= 0; ) { /* for each direction */ d = dd[r]; fsp = osp; bmask = BFLAG << r; for (f = 5; --f >= 0; fsp -= d) { /* for each frame */ if (fsp->s_occ == BORDER) goto nextr; if (fsp->s_flg & bmask) continue; /* remove this frame from the sorted list of frames */ cbp = fsp->s_frame[r]; if (cbp->c_next) { if (sortframes[BLACK] == cbp) sortframes[BLACK] = cbp->c_next; if (sortframes[WHITE] == cbp) sortframes[WHITE] = cbp->c_next; cbp->c_next->c_prev = cbp->c_prev; cbp->c_prev->c_next = cbp->c_next; } /* compute old weight value for this frame */ cp = &fsp->s_fval[BLACK][r]; if (cp->s <= 0x500) val = weight[5 - cp->c.a - cp->c.b]; else val = 0; cp = &fsp->s_fval[WHITE][r]; if (cp->s <= 0x500) val += weight[5 - cp->c.a - cp->c.b]; /* compute new combo value for this frame */ sp = fsp; space = sp->s_occ == EMPTY; n = 0; for (i = 5; --i >= 0; sp += d) { /* for each spot */ if (sp->s_occ == us) n++; else if (sp->s_occ == EMPTY) sp->s_wval -= val; else { /* this frame is now blocked, adjust values */ fsp->s_flg |= bmask; fsp->s_fval[BLACK][r].s = MAXCOMBO; fsp->s_fval[WHITE][r].s = MAXCOMBO; while (--i >= 0) { sp += d; if (sp->s_occ == EMPTY) sp->s_wval -= val; } goto nextf; } } /* check for game over */ if (n == 5) return(WIN); /* compute new value & combo number for this frame & color */ fsp->s_fval[!us][r].s = MAXCOMBO; cp = &fsp->s_fval[us][r]; /* both ends open? */ if (space && sp->s_occ == EMPTY) { cp->c.a = 4 - n; cp->c.b = 1; } else { cp->c.a = 5 - n; cp->c.b = 0; } val = weight[n]; sp = fsp; for (i = 5; --i >= 0; sp += d) /* for each spot */ if (sp->s_occ == EMPTY) sp->s_wval += val; /* add this frame to the sorted list of frames by combo value */ cbp1 = sortframes[us]; if (!cbp1) sortframes[us] = cbp->c_next = cbp->c_prev = cbp; else { cp1 = &board[cbp1->c_vertex].s_fval[us][cbp1->c_dir]; if (cp->s <= cp1->s) { /* insert at the head of the list */ sortframes[us] = cbp; } else { do { cbp1 = cbp1->c_next; cp1 = &board[cbp1->c_vertex].s_fval[us][cbp1->c_dir]; if (cp->s <= cp1->s) break; } while (cbp1 != sortframes[us]); } cbp->c_next = cbp1; cbp->c_prev = cbp1->c_prev; cbp1->c_prev->c_next = cbp; cbp1->c_prev = cbp; } nextf: ; } /* both ends open? */ if (fsp->s_occ == EMPTY) { cp = &fsp->s_fval[BLACK][r]; if (cp->c.b) { cp->c.a += 1; cp->c.b = 0; } cp = &fsp->s_fval[WHITE][r]; if (cp->c.b) { cp->c.a += 1; cp->c.b = 0; } } nextr: ; } update_overlap(osp); return(MOVEOK); } /* * fix up the overlap array due to updating spot osp. */ void update_overlap(osp) struct spotstr *osp; { struct spotstr *sp, *sp1, *sp2; int i, f, r, r1, d, d1, n; int a, b, bmask, bmask1; struct spotstr *esp = NULL; char *str; for (r = 4; --r >= 0; ) { /* for each direction */ d = dd[r]; sp1 = osp; bmask = BFLAG << r; for (f = 0; f < 6; f++, sp1 -= d) { /* for each frame */ if (sp1->s_occ == BORDER) break; if (sp1->s_flg & bmask) continue; /* * Update all other frames that intersect the current one * to indicate whether they still overlap or not. * Since F1 overlap F2 == F2 overlap F1, we only need to * do the rows 0 <= r1 <= r. The r1 == r case is special * since the two frames can overlap at more than one point. */ str = &overlap[(a = sp1->s_frame[r] - frames) * FAREA]; sp2 = sp1 - d; for (i = f + 1; i < 6; i++, sp2 -= d) { if (sp2->s_occ == BORDER) break; if (sp2->s_flg & bmask) continue; /* * count the number of empty spots to see if there is * still an overlap. */ n = 0; sp = sp1; for (b = i - f; b < 5; b++, sp += d) { if (sp->s_occ == EMPTY) { esp = sp; /* save the intersection point */ n++; } } b = sp2->s_frame[r] - frames; if (n == 0) { if (sp->s_occ == EMPTY) { str[b] &= 0xA; overlap[b * FAREA + a] &= 0xC; intersect[a * FAREA + b] = n = sp - board; intersect[b * FAREA + a] = n; } else { str[b] = 0; overlap[b * FAREA + a] = 0; } } else if (n == 1) { if (sp->s_occ == EMPTY) { str[b] &= 0xAF; overlap[b * FAREA + a] &= 0xCF; } else { str[b] &= 0xF; overlap[b * FAREA + a] &= 0xF; } intersect[a * FAREA + b] = n = esp - board; intersect[b * FAREA + a] = n; } /* else no change, still multiple overlap */ } /* the other directions can only intersect at spot osp */ for (r1 = r; --r1 >= 0; ) { d1 = dd[r1]; bmask1 = BFLAG << r1; sp = osp; for (i = 6; --i >= 0; sp -= d1) { /* for each spot */ if (sp->s_occ == BORDER) break; if (sp->s_flg & bmask1) continue; b = sp->s_frame[r1] - frames; str[b] = 0; overlap[b * FAREA + a] = 0; } } } } }