#include <sys/cdefs.h>
#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
#include <assert.h>
#include "back.h"
#include "backlocal.h"
#ifdef DEBUG
FILE *trace;
static char tests[20];
#endif
struct BOARD {
int b_board[26];
int b_in[2];
int b_off[2];
int b_st[4], b_fn[4];
struct BOARD *b_next;
};
static struct BOARD *freeq = 0;
static struct BOARD *checkq = 0;
static int ch;
static int op;
static int pt;
static int em;
static int frc;
static int frp;
static int chance;
static int openmen;
static int points;
static int endman;
static int barmen;
static int menin;
static int menoff;
static int oldfrc;
static int oldfrp;
static int cp[5];
static int cg[5];
static int 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);
void
move(struct move *mm, int okay)
{
int i;
int l;
l = 0;
if (okay) {
if (gvalue < 64 && dlast != cturn && dblgood()) {
writel(*Colorptr);
dble();
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;
if (tflag)
curmove(cturn == -1 ? 18 : 19, 0);
writel(*Colorptr);
writel(" rolls ");
writec(mm->D0 + '0');
writec(' ');
writec(mm->D1 + '0');
if (tflag)
cline();
fixtty(&noech);
mm->mvlim = movallow(mm);
if (mm->mvlim == 0) {
writel(" but cannot use it.\n");
nexturn();
fixtty(&raw);
return;
}
for (i = 0; i < 4; i++)
cp[i] = cg[i] = 0;
trymove(mm, 0, 0);
pickmove(mm);
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);
assert(mm->mvlim >= 0 && mm->mvlim <= 5);
}
writec('.');
if (tflag)
curmove(20, 0);
else
writec('\n');
for (i = 0; i < mm->mvlim; i++)
if (mm->h[i])
wrhit(mm->g[i]);
nexturn();
if (!okay) {
buflush();
sleep(3);
}
fixtty(&raw);
}
static void
trymove(struct move *mm, int mvnum, int swapped)
{
int pos;
int rval;
if (mvnum == mm->mvlim) {
binsert(mm, bsave(mm));
return;
}
if (mm->d0 == swapped)
mswap(mm);
rval = mm->dice[mvnum != 0];
for (pos = bar; pos != home; pos += cturn) {
if (mm->d0 == swapped)
mswap(mm);
if (board[bar] != 0 && pos != bar)
break;
if (board[pos] * cturn <= 0)
continue;
mm->p[mvnum] = pos;
mm->g[mvnum] = pos + rval * cturn;
if (mm->g[mvnum] * cturn >= home) {
if (*offptr < 0)
break;
mm->g[mvnum] = home;
}
if (makmove(mm, mvnum))
continue;
else
trymove(mm, mvnum + 1, 2);
backone(mm, mvnum);
}
if ((!swapped) && mm->D0 != mm->D1)
trymove(mm, 0, 1);
}
static struct BOARD *
bsave(struct move *mm)
{
int i;
struct BOARD *now;
now = nextfree();
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);
}
static void
binsert(struct move *mm, struct BOARD *new)
{
struct BOARD *qp = checkq;
int result;
if (qp == 0) {
checkq = qp = new;
qp->b_next = 0;
return;
}
result = bcomp(new, qp);
if (result < 0) {
new->b_next = qp;
checkq = new;
return;
}
if (result == 0) {
mvcheck(mm, qp, new);
makefree(new);
return;
}
while (qp->b_next != 0) {
result = bcomp(new, qp->b_next);
if (result < 0) {
new->b_next = qp->b_next;
qp->b_next = new;
return;
}
if (result == 0) {
mvcheck(mm, qp->b_next, new);
makefree(new);
return;
}
qp = qp->b_next;
}
qp->b_next = new;
new->b_next = 0;
}
static int
bcomp(struct BOARD *a, struct BOARD *b)
{
int *aloc = a->b_board;
int *bloc = b->b_board;
int i;
int result;
for (i = 0; i < 26; i++) {
result = cturn * (aloc[i] - bloc[i]);
if (result)
return (result);
}
return (0);
}
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;
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)
{
struct BOARD *now = bsave(mm);
struct BOARD *next;
#ifdef DEBUG
if (trace == NULL)
trace = fopen("bgtrace", "w");
fprintf(trace, "\nRoll: %d %d%s\n", D0, D1, race ? " (race)" : "");
fflush(trace);
#endif
do {
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;
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));
}
}