/* $OpenBSD: move.c,v 1.9 2006/12/14 10:14:05 martin Exp $ */ /* * Copyright (c) 1980, 1993 * The Regents of the University of California. All rights reserved. * * 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. */ #ifndef lint #if 0 static char sccsid[] = "@(#)move.c 8.1 (Berkeley) 5/31/93"; #else static char rcsid[] = "$OpenBSD: move.c,v 1.9 2006/12/14 10:14:05 martin Exp $"; #endif #endif /* not lint */ #include "back.h" #include "backlocal.h" struct BOARD { /* structure of game position */ int b_board[26]; /* board position */ int b_in[2]; /* men in */ int b_off[2]; /* men off */ int b_st[4], b_fn[4]; /* moves */ struct BOARD *b_next; /* forward queue pointer */ }; struct BOARD *freeq = 0; struct BOARD *checkq = 0; static int cp[5]; /* candidate start position */ static int cg[5]; /* candidate finish position */ static int race; /* game reduced to a race */ static float bestmove; static int bcomp(struct BOARD *, struct BOARD *); static struct BOARD *bsave(void); static void binsert(struct BOARD *); static void boardcopy(struct BOARD *); static void makefree(struct BOARD *); static void movcmp(void); static void mvcheck(struct BOARD *, struct BOARD *); static struct BOARD *nextfree(void); static void pickmove(void); void domove(okay) int okay; /* zero if first move */ { int i; /* index */ int l = 0; /* last man */ bestmove = -9999999.; if (okay && dflag != 0) { /* see if comp should double */ if (gvalue < 64 && dlast != cturn && dblgood()) { addstr(*Colorptr); dble(); /* double */ /* return if declined */ if (cturn != 1 && cturn != -1) return; } roll(); } race = 0; for (i = 0; i < 26; i++) { if (board[i] < 0) l = i; } for (i = 0; i < l; i++) { if (board[i] > 0) break; } if (i == l) race = 1; /* print roll */ move(cturn == -1 ? 18 : 19, 0); printw("%s rolls %d %d", *Colorptr, D0, D1); clrtoeol(); /* find out how many moves */ mvlim = movallow(); if (mvlim == 0) { addstr(" but cannot use it.\n"); nexturn(); return; } /* initialize */ for (i = 0; i < 4; i++) cp[i] = cg[i] = 0; /* strategize */ trymove(0, 0); pickmove(); /* print move */ addstr(" and moves "); for (i = 0; i < mvlim; i++) { if (i > 0) addch(','); printw("%d-%d", p[i] = cp[i], g[i] = cg[i]); makmove(i); } addch('.'); /* print blots hit */ move(20, 0); for (i = 0; i < mvlim; i++) if (h[i]) wrhit(g[i]); /* get ready for next move */ nexturn(); if (!okay) { refresh(); sleep(3); } } void trymove(mvnum, swapped) int mvnum; /* number of move (rel zero) */ int swapped; /* see if swapped also tested */ { int pos; /* position on board */ int rval; /* value of roll */ /* if recursed through all dice values, compare move */ if (mvnum == mvlim) { binsert(bsave()); return; } /* make sure dice in always same order */ if (d0 == swapped) swap; /* choose value for this move */ rval = dice[mvnum != 0]; /* find all legitimate moves */ for (pos = bar; pos != home; pos += cturn) { /* fix order of dice */ if (d0 == swapped) swap; /* break if stuck on bar */ if (board[bar] != 0 && pos != bar) break; /* on to next if not occupied */ if (board[pos] * cturn <= 0) continue; /* set up arrays for move */ p[mvnum] = pos; g[mvnum] = pos + rval * cturn; if (g[mvnum] * cturn >= home) { if (*offptr < 0) break; g[mvnum] = home; } /* try to move */ if (makmove(mvnum)) continue; else trymove(mvnum + 1, 2); /* undo move to try another */ backone(mvnum); } /* swap dice and try again */ if ((!swapped) && D0 != D1) trymove(0, 1); } static struct BOARD * bsave() { int i; /* index */ struct BOARD *now; /* current position */ now = nextfree(); /* get free BOARD */ /* store position */ for (i = 0; i < 26; i++) now->b_board[i] = board[i]; now->b_in[0] = in[0]; now->b_in[1] = in[1]; now->b_off[0] = off[0]; now->b_off[1] = off[1]; for (i = 0; i < mvlim; i++) { now->b_st[i] = p[i]; now->b_fn[i] = g[i]; } return(now); } static void binsert(new) struct BOARD *new; /* item to insert */ { struct BOARD *p = checkq; /* queue pointer */ int result; /* comparison result */ if (p == 0) { /* check if queue empty */ checkq = p = new; p->b_next = 0; return; } result = bcomp(new, p); /* compare to first element */ if (result < 0) { /* insert in front */ new->b_next = p; checkq = new; return; } if (result == 0) { /* duplicate entry */ mvcheck(p, new); makefree(new); return; } while (p->b_next != 0) {/* traverse queue */ result = bcomp(new, p->b_next); if (result < 0) { /* found place */ new->b_next = p->b_next; p->b_next = new; return; } if (result == 0) { /* duplicate entry */ mvcheck(p->b_next, new); makefree(new); return; } p = p->b_next; } /* place at end of queue */ p->b_next = new; new->b_next = 0; } static int bcomp(a, b) struct BOARD *a; struct BOARD *b; { int *aloc = a->b_board; /* pointer to board a */ int *bloc = b->b_board; /* pointer to board b */ int i; /* index */ int result; /* comparison result */ for (i = 0; i < 26; i++) { /* compare boards */ result = cturn * (aloc[i] - bloc[i]); if (result) return(result); /* found inequality */ } return(0); /* same position */ } static void mvcheck(incumbent, candidate) struct BOARD *incumbent; struct BOARD *candidate; { int i, result; for (i = 0; i < mvlim; i++) { result = cturn * (candidate->b_st[i] - incumbent->b_st[i]); if (result > 0) return; if (result < 0) break; } if (i == mvlim) return; for (i = 0; i < mvlim; i++) { incumbent->b_st[i] = candidate->b_st[i]; incumbent->b_fn[i] = candidate->b_fn[i]; } } static void makefree(dead) struct BOARD *dead; /* dead position */ { dead->b_next = freeq; /* add to freeq */ freeq = dead; } static struct BOARD * nextfree() { struct BOARD *new; if (freeq == 0) { new = (struct BOARD *)calloc (1, sizeof(struct BOARD)); if (new == 0) { addstr("\nOut of memory\n"); getout(0); } } else { new = freeq; freeq = freeq->b_next; } new->b_next = 0; return(new); } static void pickmove() { /* current game position */ struct BOARD *now = bsave(); struct BOARD *next; /* next move */ #ifdef DEBUG if (ftrace == NULL) ftrace = fopen("bgtrace", "w"); fprintf(ftrace, "\nRoll: %d %d%s\n", D0, D1, race ? " (race)" : ""); fflush(ftrace); #endif do { /* compare moves */ boardcopy(checkq); next = checkq->b_next; makefree(checkq); checkq = next; movcmp(); } while (checkq != 0); boardcopy(now); } static void boardcopy(s) struct BOARD *s; /* game situation */ { int i; /* index */ for (i = 0; i < 26; i++) board[i] = s->b_board[i]; for (i = 0; i < 2; i++) { in[i] = s->b_in[i]; off[i] = s->b_off[i]; } for (i = 0; i < mvlim; i++) { p[i] = s->b_st[i]; g[i] = s->b_fn[i]; } } static void movcmp() { int i; float f; setx(); f = pubeval(race); if (f > bestmove) { bestmove = f; for (i = 0; i < mvlim; i++) { cp[i] = p[i]; cg[i] = g[i]; } } }