/* $NetBSD: move.c,v 1.13 2012/10/13 19:39:57 dholland 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. */ #include #ifndef lint #if 0 static char sccsid[] = "@(#)move.c 8.1 (Berkeley) 5/31/93"; #else __RCSID("$NetBSD: move.c,v 1.13 2012/10/13 19:39:57 dholland Exp $"); #endif #endif /* not lint */ #include #include "back.h" #include "backlocal.h" #ifdef DEBUG FILE *trace; static char tests[20]; #endif 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 */ }; static struct BOARD *freeq = 0; static struct BOARD *checkq = 0; /* these variables are values for the candidate move */ static int ch; /* chance of being hit */ static int op; /* computer's open men */ static int pt; /* comp's protected points */ static int em; /* farthest man back */ static int frc; /* chance to free comp's men */ static int frp; /* chance to free pl's men */ /* these values are the values for the move chosen (so far) */ static int chance; /* chance of being hit */ static int openmen; /* computer's open men */ static int points; /* comp's protected points */ static int endman; /* farthest man back */ static int barmen; /* men on bar */ static int menin; /* men in inner table */ static int menoff; /* men off board */ static int oldfrc; /* chance to free comp's men */ static int oldfrp; /* chance to free pl's men */ static int cp[5]; /* candidate start position */ static int cg[5]; /* candidate finish position */ static int race; /* game reduced to a race */ static int bcomp(struct BOARD *, struct BOARD *); static struct BOARD *bsave(struct move *); static void binsert(struct move *, struct BOARD *); static void boardcopy(struct move *, struct BOARD *); static void makefree(struct BOARD *); static void mvcheck(struct move *, struct BOARD *, struct BOARD *); static struct BOARD *nextfree(void); static void trymove(struct move *, int, int); static void pickmove(struct move *); static void movcmp(struct move *); static int movegood(void); /* zero if first move */ void move(struct move *mm, int okay) { int i; /* index */ int l; /* last man */ l = 0; if (okay) { /* see if comp should double */ if (gvalue < 64 && dlast != cturn && dblgood()) { writel(*Colorptr); dble(); /* double */ /* return if declined */ if (cturn != 1 && cturn != -1) return; } roll(mm); } 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 */ if (tflag) curmove(cturn == -1 ? 18 : 19, 0); writel(*Colorptr); writel(" rolls "); writec(mm->D0 + '0'); writec(' '); writec(mm->D1 + '0'); /* make tty interruptable while thinking */ if (tflag) cline(); fixtty(&noech); /* find out how many moves */ mm->mvlim = movallow(mm); if (mm->mvlim == 0) { writel(" but cannot use it.\n"); nexturn(); fixtty(&raw); return; } /* initialize */ for (i = 0; i < 4; i++) cp[i] = cg[i] = 0; /* strategize */ trymove(mm, 0, 0); pickmove(mm); /* print move */ writel(" and moves "); for (i = 0; i < mm->mvlim; i++) { if (i > 0) writec(','); wrint(mm->p[i] = cp[i]); writec('-'); wrint(mm->g[i] = cg[i]); makmove(mm, i); /* * This assertion persuades gcc 4.5 that the loop * doesn't result in signed overflow of i. mvlim * isn't, or at least shouldn't be, changed by makmove * at all. */ assert(mm->mvlim >= 0 && mm->mvlim <= 5); } writec('.'); /* print blots hit */ if (tflag) curmove(20, 0); else writec('\n'); for (i = 0; i < mm->mvlim; i++) if (mm->h[i]) wrhit(mm->g[i]); /* get ready for next move */ nexturn(); if (!okay) { buflush(); sleep(3); } fixtty(&raw); /* no more tty interrupt */ } /* mvnum == number of move (rel zero) */ /* swapped == see if swapped also tested */ static void trymove(struct move *mm, int mvnum, int swapped) { int pos; /* position on board */ int rval; /* value of roll */ /* if recursed through all dice values, compare move */ if (mvnum == mm->mvlim) { binsert(mm, bsave(mm)); return; } /* make sure dice in always same order */ if (mm->d0 == swapped) mswap(mm); /* choose value for this move */ rval = mm->dice[mvnum != 0]; /* find all legitimate moves */ for (pos = bar; pos != home; pos += cturn) { /* fix order of dice */ if (mm->d0 == swapped) mswap(mm); /* 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 */ mm->p[mvnum] = pos; mm->g[mvnum] = pos + rval * cturn; if (mm->g[mvnum] * cturn >= home) { if (*offptr < 0) break; mm->g[mvnum] = home; } /* try to move */ if (makmove(mm, mvnum)) continue; else trymove(mm, mvnum + 1, 2); /* undo move to try another */ backone(mm, mvnum); } /* swap dice and try again */ if ((!swapped) && mm->D0 != mm->D1) trymove(mm, 0, 1); } static struct BOARD * bsave(struct move *mm) { 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 < mm->mvlim; i++) { now->b_st[i] = mm->p[i]; now->b_fn[i] = mm->g[i]; } return (now); } /* new == item to insert */ static void binsert(struct move *mm, struct BOARD *new) { struct BOARD *qp = checkq; /* queue pointer */ int result; /* comparison result */ if (qp == 0) { /* check if queue empty */ checkq = qp = new; qp->b_next = 0; return; } result = bcomp(new, qp); /* compare to first element */ if (result < 0) { /* insert in front */ new->b_next = qp; checkq = new; return; } if (result == 0) { /* duplicate entry */ mvcheck(mm, qp, new); makefree(new); return; } while (qp->b_next != 0) {/* traverse queue */ result = bcomp(new, qp->b_next); if (result < 0) { /* found place */ new->b_next = qp->b_next; qp->b_next = new; return; } if (result == 0) { /* duplicate entry */ mvcheck(mm, qp->b_next, new); makefree(new); return; } qp = qp->b_next; } /* place at end of queue */ qp->b_next = new; new->b_next = 0; } static int bcomp(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(struct move *mm, struct BOARD *incumbent, struct BOARD *candidate) { int i; int result; for (i = 0; i < mm->mvlim; i++) { result = cturn * (candidate->b_st[i] - incumbent->b_st[i]); if (result > 0) return; if (result < 0) break; } if (i == mm->mvlim) return; for (i = 0; i < mm->mvlim; i++) { incumbent->b_st[i] = candidate->b_st[i]; incumbent->b_fn[i] = candidate->b_fn[i]; } } void makefree(struct BOARD *dead) { dead->b_next = freeq; /* add to freeq */ freeq = dead; } static struct BOARD * nextfree(void) { struct BOARD *new; if (freeq == 0) { new = (struct BOARD *) calloc(1, sizeof(struct BOARD)); if (new == 0) { writel("\nOut of memory\n"); getout(0); } } else { new = freeq; freeq = freeq->b_next; } new->b_next = 0; return (new); } static void pickmove(struct move *mm) { /* current game position */ struct BOARD *now = bsave(mm); struct BOARD *next; /* next move */ #ifdef DEBUG if (trace == NULL) trace = fopen("bgtrace", "w"); fprintf(trace, "\nRoll: %d %d%s\n", D0, D1, race ? " (race)" : ""); fflush(trace); #endif do { /* compare moves */ boardcopy(mm, checkq); next = checkq->b_next; makefree(checkq); checkq = next; movcmp(mm); } while (checkq != 0); boardcopy(mm, now); } static void boardcopy(struct move *mm, struct BOARD *s) { 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 < mm->mvlim; i++) { mm->p[i] = s->b_st[i]; mm->g[i] = s->b_fn[i]; } } static void movcmp(struct move *mm) { int i; #ifdef DEBUG if (trace == NULL) trace = fopen("bgtrace", "w"); #endif odds(0, 0, 0); if (!race) { ch = op = pt = 0; for (i = 1; i < 25; i++) { if (board[i] == cturn) ch = canhit(i, 1); op += abs(bar - i); } for (i = bar + cturn; i != home; i += cturn) if (board[i] * cturn > 1) pt += abs(bar - i); frc = freemen(bar) + trapped(bar, cturn); frp = freemen(home) + trapped(home, -cturn); } for (em = bar; em != home; em += cturn) if (board[em] * cturn > 0) break; em = abs(home - em); #ifdef DEBUG fputs("Board: ", trace); for (i = 0; i < 26; i++) fprintf(trace, " %d", board[i]); if (race) fprintf(trace, "\n\tem = %d\n", em); else fprintf(trace, "\n\tch = %d, pt = %d, em = %d, frc = %d, frp = %d\n", ch, pt, em, frc, frp); fputs("\tMove: ", trace); for (i = 0; i < mvlim; i++) fprintf(trace, " %d-%d", p[i], g[i]); fputs("\n", trace); fflush(trace); strcpy(tests, ""); #endif if ((cp[0] == 0 && cg[0] == 0) || movegood()) { #ifdef DEBUG fprintf(trace, "\t[%s] ... wins.\n", tests); fflush(trace); #endif for (i = 0; i < mm->mvlim; i++) { cp[i] = mm->p[i]; cg[i] = mm->g[i]; } if (!race) { chance = ch; openmen = op; points = pt; endman = em; barmen = abs(board[home]); oldfrc = frc; oldfrp = frp; } menin = *inptr; menoff = *offptr; } #ifdef DEBUG else { fprintf(trace, "\t[%s] ... loses.\n", tests); fflush(trace); } #endif } static int movegood(void) { int n; if (*offptr == 15) return (1); if (menoff == 15) return (0); if (race) { #ifdef DEBUG strcat(tests, "o"); #endif if (*offptr - menoff) return (*offptr > menoff); #ifdef DEBUG strcat(tests, "e"); #endif if (endman - em) return (endman > em); #ifdef DEBUG strcat(tests, "i"); #endif if (menin == 15) return (0); if (*inptr == 15) return (1); #ifdef DEBUG strcat(tests, "i"); #endif if (*inptr - menin) return (*inptr > menin); return (rnum(2)); } else { n = barmen - abs(board[home]); #ifdef DEBUG strcat(tests, "c"); #endif if (abs(chance - ch) + 25 * n > rnum(150)) return (n ? (n < 0) : (ch < chance)); #ifdef DEBUG strcat(tests, "o"); #endif if (*offptr - menoff) return (*offptr > menoff); #ifdef DEBUG strcat(tests, "o"); #endif if (abs(openmen - op) > 7 + rnum(12)) return (openmen > op); #ifdef DEBUG strcat(tests, "b"); #endif if (n) return (n < 0); #ifdef DEBUG strcat(tests, "e"); #endif if (abs(endman - em) > rnum(2)) return (endman > em); #ifdef DEBUG strcat(tests, "f"); #endif if (abs(frc - oldfrc) > rnum(2)) return (frc < oldfrc); #ifdef DEBUG strcat(tests, "p"); #endif if (abs(n = pt - points) > rnum(4)) return (n > 0); #ifdef DEBUG strcat(tests, "i"); #endif if (*inptr - menin) return (*inptr > menin); #ifdef DEBUG strcat(tests, "f"); #endif if (abs(frp - oldfrp) > rnum(2)) return (frp > oldfrp); return (rnum(2)); } }