866 lines
22 KiB
C
866 lines
22 KiB
C
|
|
|||
|
/* Gammon IV, by David C. Oshel, Ames, Iowa */
|
|||
|
|
|||
|
/*--------------------------------------------------------------------*/
|
|||
|
/* GAMEPLAN.C -- separately compiled module, contains the tactics and */
|
|||
|
/* strategy for making the computer's move in Gammon IV */
|
|||
|
/* BACKGMMN.REL calls MyMove(), MyMove() calls topstone */
|
|||
|
/* and movestone and a few others. Uses the globals in */
|
|||
|
/* GAMEPLAN.HDR quite heavily. Bgversion declared here */
|
|||
|
/*--------------------------------------------------------------------*/
|
|||
|
|
|||
|
#include "gameplan.hdr" /* contains external, global declarations */
|
|||
|
|
|||
|
/*-------------------------------------------------------------------------*/
|
|||
|
/* */
|
|||
|
/* Bgversion is an external reference in the main module. Use this string */
|
|||
|
/* to take credit for a decent gameplaying algorithm if you find one! */
|
|||
|
/* */
|
|||
|
char *bgversion = ".20 -April 1, 1986- by David C. Oshel";
|
|||
|
/*....v....1....v....2....v....3....v...*/
|
|||
|
/* just 38 characters for version info! */
|
|||
|
/* */
|
|||
|
/*-------------------------------------------------------------------------*/
|
|||
|
|
|||
|
|
|||
|
/*=============================================*/
|
|||
|
/* M Y M O V E */
|
|||
|
/*=============================================*/
|
|||
|
|
|||
|
|
|||
|
naked() { /* am I leaving too many blots? */
|
|||
|
static int i, clink;
|
|||
|
i = 24; clink = 0;
|
|||
|
while (i) {
|
|||
|
if (point[i].stones == 1 && point[i].owner == ME) clink++;
|
|||
|
i--;
|
|||
|
}
|
|||
|
return (clink > 2);
|
|||
|
} /* end: naked */
|
|||
|
|
|||
|
|
|||
|
yourfolly() { /* look for lotsa blots in your inner table */
|
|||
|
static int i, clink;
|
|||
|
i = 18; clink = 0;
|
|||
|
while (i < 25) {
|
|||
|
if (point[i].owner == YU && point[i].stones == 1)
|
|||
|
clink++;
|
|||
|
i++;
|
|||
|
}
|
|||
|
return (clink >= 3);
|
|||
|
} /* end: yourfolly */
|
|||
|
|
|||
|
|
|||
|
goodboard() { /* look for four made points near my inner table */
|
|||
|
static int i, clank, clink;
|
|||
|
i = 9; clank = 0;
|
|||
|
while (i > 3) {
|
|||
|
if (point[i].owner == ME && point[i].stones > 1) clank++;
|
|||
|
i--;
|
|||
|
}
|
|||
|
if (clank > 4) return (TRUE); /* bar is nearly blocked */
|
|||
|
|
|||
|
i = 6; clank = clink = 0;
|
|||
|
while (i) {
|
|||
|
if (point[i].owner != ME)
|
|||
|
;
|
|||
|
else if (point[i].stones == 1) clink++; else clank++;
|
|||
|
i--;
|
|||
|
}
|
|||
|
return (clank > 3 && clink < 2);
|
|||
|
} /* end: goodboard */
|
|||
|
|
|||
|
|
|||
|
bearoff() {
|
|||
|
return (topstone(ME) < 7);
|
|||
|
} /* end: bearoff */
|
|||
|
|
|||
|
|
|||
|
scanahead( from ) int from; {
|
|||
|
static int count;
|
|||
|
|
|||
|
count = 0;
|
|||
|
while (--from > 0) {
|
|||
|
++count;
|
|||
|
if ( point[ from ].owner == YU ) return (count);
|
|||
|
}
|
|||
|
return (7);
|
|||
|
|
|||
|
} /* end: scanahead */
|
|||
|
|
|||
|
|
|||
|
endgame() { /* Is no strategy required from here on in? */
|
|||
|
return ( (25 - topstone(YU)) > topstone(ME) );
|
|||
|
} /* end: endgame */
|
|||
|
|
|||
|
|
|||
|
/*------------------------------------------------------------*/
|
|||
|
/* MATCHUP */
|
|||
|
/* */
|
|||
|
/* 2-stone functions that force the choice of the next move. */
|
|||
|
/* These are the HEART and SOUL of this backgammon algorithm! */
|
|||
|
/*------------------------------------------------------------*/
|
|||
|
|
|||
|
setpend( from, to ) int from, to; {
|
|||
|
pending.fr = from;
|
|||
|
pending.to = to;
|
|||
|
pending.flag = TRUE;
|
|||
|
} /* end: setpend */
|
|||
|
|
|||
|
|
|||
|
clrpend() {
|
|||
|
pending.flag = FALSE;
|
|||
|
} /* end: clrpend */
|
|||
|
|
|||
|
|
|||
|
natural(f1,t1,f2,t2) int f1,t1,f2,t2; {
|
|||
|
clrpend();
|
|||
|
if (point[t2].stones == 1 && t1 == f2) setpend(f2,t2);
|
|||
|
return (pending.flag);
|
|||
|
} /* end: natural */
|
|||
|
|
|||
|
|
|||
|
matchup( test4 ) int (* test4)(); {
|
|||
|
static int i, j, ti, tj;
|
|||
|
|
|||
|
if ( pending.flag ) return (FALSE); /* this is probably redundant */
|
|||
|
|
|||
|
for (i = 1; i < 26; i++) {
|
|||
|
ti = list[0][i];
|
|||
|
if ( ti == ERROR ) goto zoo;
|
|||
|
for (j = 1; j < 26; j++) {
|
|||
|
tj = list[1][j];
|
|||
|
if ( tj == ERROR ) goto voo;
|
|||
|
if ( (* test4)( i, ti, j, tj ) ) {
|
|||
|
lurch( i, ti, 0);
|
|||
|
return (TRUE);
|
|||
|
}
|
|||
|
voo: ;
|
|||
|
}
|
|||
|
zoo: ;
|
|||
|
}
|
|||
|
return (FALSE);
|
|||
|
|
|||
|
} /* end: matchup */
|
|||
|
|
|||
|
|
|||
|
matchhi( test4 ) int (* test4)(); {
|
|||
|
static int i, j, ti, tj;
|
|||
|
|
|||
|
if ( pending.flag ) return (FALSE); /* this is probably redundant */
|
|||
|
|
|||
|
for (i = 1; i < 26; i++) {
|
|||
|
ti = list[1][i];
|
|||
|
if ( ti == ERROR ) goto zoo;
|
|||
|
for (j = 1; j < 26; j++) {
|
|||
|
tj = list[0][j];
|
|||
|
if ( tj == ERROR ) goto voo;
|
|||
|
if ( (* test4)( i, ti, j, tj ) ) {
|
|||
|
lurch( i, ti, 1);
|
|||
|
return (TRUE);
|
|||
|
}
|
|||
|
voo: ;
|
|||
|
}
|
|||
|
zoo: ;
|
|||
|
}
|
|||
|
return (FALSE);
|
|||
|
|
|||
|
} /* end: matchhi */
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*--------------------------------------------------------*/
|
|||
|
/* CLOCKWISE and COUNTERCLOCK */
|
|||
|
/* */
|
|||
|
/* the rest of these are single-stone decisions based on */
|
|||
|
/* rules of thumb, board-scanning functions */
|
|||
|
/*--------------------------------------------------------*/
|
|||
|
|
|||
|
plainstupid( from ) int from; { /* don't break a safe point */
|
|||
|
return (from < 13 && (point[from].stones == 2 && scanahead(from) < 7));
|
|||
|
} /* end: plainstupid */
|
|||
|
|
|||
|
|
|||
|
unwise( innertablept ) int innertablept; {
|
|||
|
/* if it's a hit, just for god's sake don't put him on the bar!! */
|
|||
|
if ( innertablept < 7 ) {
|
|||
|
if (point[ innertablept ].owner == YU ||
|
|||
|
point[ YRBAR ].stones > 0)
|
|||
|
return (TRUE);
|
|||
|
}
|
|||
|
return(FALSE);
|
|||
|
} /* end: unwise */
|
|||
|
|
|||
|
|
|||
|
|
|||
|
covermine( from, to ) int from, to; {
|
|||
|
if ( from < 8 ) return(FALSE);
|
|||
|
return ( (point[ to ].stones == 1) && (point[ to ].owner == ME) );
|
|||
|
} /* end: covermine */
|
|||
|
|
|||
|
|
|||
|
idareyou( from, to ) int from, to; {
|
|||
|
if (unwise( to )) return (FALSE);
|
|||
|
if ( (point[ from ].stones != 2)
|
|||
|
&& (point[ to ].stones < 2)
|
|||
|
&& (scanahead( to ) > 6) ) return ( TRUE );
|
|||
|
else return (FALSE);
|
|||
|
} /* end: idareyou */
|
|||
|
|
|||
|
|
|||
|
hitandrun( from, to ) int from, to; {
|
|||
|
return ( point[ to ].owner == YU );
|
|||
|
} /* end: hitandrun */
|
|||
|
|
|||
|
|
|||
|
dbuild( from, to ) int from, to; {
|
|||
|
static int diceleft;
|
|||
|
diceleft = (myturns? 2 + movesleft: movesleft);
|
|||
|
if (diceleft > 1) {
|
|||
|
/* can't possibly be only one stone on from point */
|
|||
|
/* or kamikaze would have covered it on last move */
|
|||
|
return ( point[to].stones == 0 );
|
|||
|
}
|
|||
|
return (FALSE);
|
|||
|
} /* end: dbuild */
|
|||
|
|
|||
|
|
|||
|
kamikaze( from, to ) int from, to; {
|
|||
|
/* cover my distant blot, or razzle-dazzle 'em with the long doubles hit */
|
|||
|
static int j, k, diceleft;
|
|||
|
|
|||
|
k = from;
|
|||
|
j = from - to;
|
|||
|
diceleft = myturns * movesleft; /* NB: 2*2 == 2+2, "fourtunately" */
|
|||
|
while ( diceleft-- ) { /* predicting where doubles land is easy! */
|
|||
|
k -= j;
|
|||
|
if (k < 1) return (FALSE); /* out of bounds */
|
|||
|
if ( point[ k ].stones == 0 ) continue; /* simplify */
|
|||
|
if ( point[ k ].stones == 1 ) /* found my blot or yours? */
|
|||
|
return (TRUE);
|
|||
|
else if ( point[k].owner == YU ) /* found your blockade? */
|
|||
|
return (FALSE);
|
|||
|
else continue; /* found my safe point, so ignore it */
|
|||
|
}
|
|||
|
return (FALSE);
|
|||
|
|
|||
|
} /* end: kamikaze */
|
|||
|
|
|||
|
|
|||
|
hittite( from, to ) int from, to; {
|
|||
|
return (hitandrun(from,to) && to > 9);
|
|||
|
} /* end: hittite */
|
|||
|
|
|||
|
|
|||
|
safehit( from, to ) int from, to; {
|
|||
|
return (hittite(from,to) && idareyou(from,to));
|
|||
|
} /* end: safehit */
|
|||
|
|
|||
|
|
|||
|
foolsdemise( from, to ) int from, to; {
|
|||
|
/* annihilate orphaned blots in enemy's inner, my outer table */
|
|||
|
return (to > 17 && point[to].owner == YU);
|
|||
|
} /* end: foolsdemise */
|
|||
|
|
|||
|
|
|||
|
landonme( from, to ) int from, to; {
|
|||
|
if ( plainstupid(from) ) return (FALSE);
|
|||
|
if ( loneranger(from,to) ) {
|
|||
|
if (from < 19 && to > 6) return(TRUE);
|
|||
|
}
|
|||
|
else return ( point[ to ].owner == ME && point[to].stones < 4);
|
|||
|
} /* end: landonme */
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* these evaluations have meaning only in the endgame */
|
|||
|
|
|||
|
|
|||
|
nobackgammon( from, to ) int from, to; { /* endgame */
|
|||
|
return (from > 19);
|
|||
|
} /* end: nobackgammon */
|
|||
|
|
|||
|
|
|||
|
crosstable( from, to ) int from, to; {
|
|||
|
/* always move a table ahead if possible, in the endgame */
|
|||
|
if (from < 7) return (FALSE);
|
|||
|
if (from > 18 && to <= 18) return (TRUE);
|
|||
|
if (from > 12 && to <= 12) return (TRUE);
|
|||
|
if (from > 6 && to <= 6) return (TRUE);
|
|||
|
return (FALSE);
|
|||
|
} /* end: crosstable */
|
|||
|
|
|||
|
|
|||
|
fiftytworule( from, to ) int from, to; { /* endgame */
|
|||
|
static int p;
|
|||
|
if (from < 7) return (FALSE); /* not in inner table! */
|
|||
|
p = from % 6;
|
|||
|
if (p == 0) return (TRUE); /* improve the six */
|
|||
|
if (p != 5) return ( (to % 6) < 3 ); /* best improve under five */
|
|||
|
} /* end: fiftytworule */
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* these evaluations are universally applicable, last resort moves */
|
|||
|
|
|||
|
|
|||
|
gohome( from, to ) int from, to; { /* always go home if you can */
|
|||
|
return (to == MYHOME);
|
|||
|
} /* end: gohome */
|
|||
|
|
|||
|
|
|||
|
scatter( from, to ) int from, to; { /* scatter, esp. in the endgame */
|
|||
|
if (plainstupid(from) || unwise(to)) return (FALSE);
|
|||
|
return ( point[ from ].stones > 1 && point[ to ].stones == 0 );
|
|||
|
} /* end: scatter */
|
|||
|
|
|||
|
|
|||
|
runnerup( from, to ) int from, to; {
|
|||
|
if (from < 10 || from > 18) return (FALSE);
|
|||
|
return (TRUE);
|
|||
|
} /* end: runnerup */
|
|||
|
|
|||
|
|
|||
|
loneranger( from, to ) int from, to; {
|
|||
|
return( point[ from ].stones == 1 );
|
|||
|
} /* end: loneranger */
|
|||
|
|
|||
|
|
|||
|
run( dummy1, dummy2 ) int dummy1, dummy2; { /* MUST move something! */
|
|||
|
return (TRUE);
|
|||
|
} /* end: run */
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* clockwise and counterclock make a 1-stone choice on rules of thumb */
|
|||
|
|
|||
|
|
|||
|
counterclock( test ) int (* test)(); {
|
|||
|
static int i,j;
|
|||
|
|
|||
|
for (i = 0; i < 2; i++) {
|
|||
|
for (j = 1; j < 25; j++) {
|
|||
|
if ( list[i][j] == ERROR ) continue;
|
|||
|
if ( (* test)( j, list[i][j] ) ) {
|
|||
|
lurch( j, list[i][j], i);
|
|||
|
return ( TRUE );
|
|||
|
} } }
|
|||
|
return (FALSE);
|
|||
|
|
|||
|
} /* end: counterclock */
|
|||
|
|
|||
|
|
|||
|
clockwise( test ) int (* test)(); {
|
|||
|
static int i,j;
|
|||
|
|
|||
|
for (i = 0; i < 2; i++) {
|
|||
|
for (j = 25; j > 0; j--) {
|
|||
|
if ( list[i][j] == ERROR ) continue;
|
|||
|
if ( (* test)( j, list[i][j] ) ) {
|
|||
|
lurch( j, list[i][j], i);
|
|||
|
return ( TRUE );
|
|||
|
} } }
|
|||
|
return (FALSE);
|
|||
|
|
|||
|
} /* end: clockwise */
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*-------------------------------------------*/
|
|||
|
/* Make Prime */
|
|||
|
/*-------------------------------------------*/
|
|||
|
|
|||
|
static int prmchk;
|
|||
|
|
|||
|
|
|||
|
buildprime( f1,t1,f2,t2 ) int f1,t1,f2,t2; {
|
|||
|
clrpend();
|
|||
|
/* check for the doubles bug */
|
|||
|
if ((dice[0] == dice[1]) && (point[f1].stones < 2)) return(FALSE);
|
|||
|
|
|||
|
/* look for the combination */
|
|||
|
if ( t1 == prmchk && t2 == prmchk) setpend(f2,t2);
|
|||
|
|
|||
|
/* stick like glue to a made point, but doubles may move forward */
|
|||
|
if (dice[0] != dice[1]) {
|
|||
|
if ((f2 < 8) && (point[f2].stones == 2)) clrpend();
|
|||
|
if ((f1 < 8) && (point[f1].stones == 2)) clrpend();
|
|||
|
}
|
|||
|
|
|||
|
return(pending.flag);
|
|||
|
|
|||
|
} /* end: buildprime */
|
|||
|
|
|||
|
|
|||
|
makeprime() {
|
|||
|
static int i, tab[] = { ERROR,1,2,3,20,22,24,9,4,6,8,5,7 };
|
|||
|
i = 12;
|
|||
|
while (i) {
|
|||
|
prmchk = tab[i];
|
|||
|
i--;
|
|||
|
if ( point[ prmchk ].stones > 1 ) continue;
|
|||
|
else if ( matchup( buildprime ) ) return(TRUE);
|
|||
|
}
|
|||
|
return(FALSE);
|
|||
|
} /* end: makeprime */
|
|||
|
|
|||
|
|
|||
|
coverprime( from, to ) int from, to; {
|
|||
|
return (((to == prmchk) &&
|
|||
|
(point[prmchk].owner == ME)) &&
|
|||
|
(point[from].stones != 2));
|
|||
|
} /* coverprime */
|
|||
|
|
|||
|
|
|||
|
cleanup() {
|
|||
|
static int i, tab[] = { ERROR,1,2,3,20,22,24,9,4,6,8,5,7 };
|
|||
|
i = 12;
|
|||
|
while (i) {
|
|||
|
prmchk = tab[i];
|
|||
|
i--;
|
|||
|
if ( point[ prmchk ].stones != 1 ) continue;
|
|||
|
else if ( counterclock( coverprime ) ) return(TRUE);
|
|||
|
}
|
|||
|
return(FALSE);
|
|||
|
} /* end: cleanup */
|
|||
|
|
|||
|
|
|||
|
/*-------------------------------------*/
|
|||
|
/* Walking Prime */
|
|||
|
/*-------------------------------------*/
|
|||
|
|
|||
|
swivelhips( from, to ) int from, to; {
|
|||
|
return ( from > prmchk );
|
|||
|
} /* end: swivelhips */
|
|||
|
|
|||
|
|
|||
|
slink( from, to ) int from, to; {
|
|||
|
return( (from > prmchk) && (point[to].stones == 1) );
|
|||
|
} /* end: slink */
|
|||
|
|
|||
|
|
|||
|
weasel() {
|
|||
|
if ( clockwise( slink ) )
|
|||
|
return(TRUE);
|
|||
|
if ( counterclock( swivelhips ) )
|
|||
|
return(TRUE);
|
|||
|
if ( clockwise( run ) )
|
|||
|
return(TRUE);
|
|||
|
} /* end: weasel */
|
|||
|
|
|||
|
ihaveprime( from ) int from; {
|
|||
|
static int i, to, ez;
|
|||
|
ez = 0;
|
|||
|
for (i = 0; i < 6; i++) {
|
|||
|
to = from - i;
|
|||
|
if ((point[to].owner == ME) && (point[to].stones > 1)) ez++;
|
|||
|
}
|
|||
|
return (ez > 4);
|
|||
|
} /* end: ihaveprime */
|
|||
|
|
|||
|
|
|||
|
walkingprime() {
|
|||
|
/* looks for the walking prime anywhere in the front tables */
|
|||
|
/* then tries to bring up a runner from behind the prime, */
|
|||
|
/* ensuring that a back stone WILL move before a front one */
|
|||
|
static int i;
|
|||
|
i = 12;
|
|||
|
while (i > 5) {
|
|||
|
if ( ihaveprime(i) ) {
|
|||
|
prmchk = i;
|
|||
|
if ( weasel() ) return (TRUE);
|
|||
|
}
|
|||
|
i--;
|
|||
|
}
|
|||
|
return(FALSE);
|
|||
|
} /* end: walkingprime */
|
|||
|
|
|||
|
|
|||
|
/*---------- Book Moves ----------*/
|
|||
|
/* only valid if my move is first */
|
|||
|
/*--------------------------------*/
|
|||
|
|
|||
|
zip(a,b,c,d) int a,b,c,d; {
|
|||
|
lurch(a,b,0);
|
|||
|
lurch(c,d,0);
|
|||
|
movesleft = 0; return( TRUE );
|
|||
|
} /* end: zip */
|
|||
|
|
|||
|
|
|||
|
zoom( a,b,c,d,e,f,g,h ) int a,b,c,d,e,f,g,h; {
|
|||
|
myturns = 0; zip(a,b,c,d); zip(e,f,g,h); return( TRUE );
|
|||
|
} /* end: zoom */
|
|||
|
|
|||
|
|
|||
|
book() {
|
|||
|
int a,b;
|
|||
|
if (!firstmove) return (FALSE);
|
|||
|
firstmove = FALSE;
|
|||
|
a = min(dice[0],dice[1]);
|
|||
|
b = max(dice[0],dice[1]);
|
|||
|
switch (level) {
|
|||
|
case 0: { return ( book0(a,b) ); break; }
|
|||
|
case 1: { return ( book1(a,b) ); break; }
|
|||
|
case 2: { return ( book2(a,b) ); break; }
|
|||
|
}
|
|||
|
}
|
|||
|
book0( a,b ) int a, b; {
|
|||
|
switch (a) {
|
|||
|
case 1: { switch (b) {
|
|||
|
case 1: return ( zoom(8,7,8,7,6,5,6,5) );
|
|||
|
case 2: return ( zip(24,23,13,11) );
|
|||
|
case 3: return ( zip(8,5,6,5) );
|
|||
|
case 4: return ( zip(24,23,13,9) );
|
|||
|
case 5: return ( zip(24,23,13,8) );
|
|||
|
case 6: return ( zip(13,7,8,7) );
|
|||
|
}
|
|||
|
break; }
|
|||
|
case 2: { switch (b) {
|
|||
|
case 2: return ( zoom(6,4,6,4,13,11,13,11) );
|
|||
|
case 3: return ( zip(13,11,13,10) );
|
|||
|
case 4: return ( zip(8,4,6,4) );
|
|||
|
case 5: return ( zip(13,8,13,11) );
|
|||
|
case 6: return ( zip(24,18,13,11) );
|
|||
|
}
|
|||
|
break; }
|
|||
|
case 3: { switch (b) {
|
|||
|
case 3: return ( zoom(13,10,13,10,10,7,10,7) );
|
|||
|
case 4: return ( zip(13,10,13,9) );
|
|||
|
case 5: return ( zip(13,10,13,8) );
|
|||
|
case 6: return ( zip(24,18,13,10) );
|
|||
|
}
|
|||
|
break; }
|
|||
|
case 4: { switch (b) {
|
|||
|
case 4: return ( zoom(13,9,13,9,24,20,24,20) );
|
|||
|
case 5: return ( zip(13,8,13,9) );
|
|||
|
case 6: return ( zip(24,18,18,14) );
|
|||
|
}
|
|||
|
break; }
|
|||
|
case 5: { switch (b) {
|
|||
|
case 5: return ( zoom(13,8,13,8,8,3,8,3) );
|
|||
|
case 6: return ( zip(24,18,18,13) );
|
|||
|
}
|
|||
|
break; }
|
|||
|
case 6: { return ( zoom(13,7,13,7,24,18,24,18) );
|
|||
|
break; }
|
|||
|
}
|
|||
|
|
|||
|
} /* end: book0 */
|
|||
|
book1( a,b ) int a, b; { /* mostly follows Becker */
|
|||
|
switch (a) {
|
|||
|
case 1: { switch (b) {
|
|||
|
case 1: return ( zoom(8,7,8,7,6,5,6,5) );
|
|||
|
case 2: return ( zip(13,11,6,5) );
|
|||
|
case 3: return ( zip(8,5,6,5) );
|
|||
|
case 4: return ( zip(13,9,6,5) );
|
|||
|
case 5: return ( zip(13,8,6,5) );
|
|||
|
case 6: return ( zip(13,7,8,7) );
|
|||
|
}
|
|||
|
break; }
|
|||
|
case 2: { switch (b) {
|
|||
|
case 2: return ( zoom(6,4,6,4,13,11,13,11) );
|
|||
|
case 3: return ( zip(13,11,13,10) );
|
|||
|
case 4: return ( zip(8,4,6,4) );
|
|||
|
case 5: return ( zip(13,8,13,11) );
|
|||
|
case 6: return ( zip(13,7,7,5) );
|
|||
|
}
|
|||
|
break; }
|
|||
|
case 3: { switch (b) {
|
|||
|
case 3: return ( zoom(13,10,13,10,8,5,8,5) );
|
|||
|
case 4: return ( zip(13,10,13,9) );
|
|||
|
case 5: return ( zip(13,8,8,5) );
|
|||
|
case 6: return ( zip(13,7,13,10) );
|
|||
|
}
|
|||
|
break; }
|
|||
|
case 4: { switch (b) {
|
|||
|
case 4: return ( zoom(13,9,13,9,9,5,9,5) );
|
|||
|
case 5: return ( zip(13,8,13,9) );
|
|||
|
case 6: return ( zip(13,7,13,9) );
|
|||
|
}
|
|||
|
break; }
|
|||
|
case 5: { switch (b) {
|
|||
|
case 5: return ( zoom(13,8,13,8,8,3,8,3) );
|
|||
|
case 6: return ( zip(13,7,13,8) );
|
|||
|
}
|
|||
|
break; }
|
|||
|
case 6: { return ( zoom(13,7,13,7,24,18,24,18) );
|
|||
|
break; }
|
|||
|
}
|
|||
|
|
|||
|
} /* end: book1 */
|
|||
|
book2( a,b ) int a, b; { /* mostly follows Becker */
|
|||
|
switch (a) {
|
|||
|
case 1: { switch (b) {
|
|||
|
case 1: return ( zoom(8,7,8,7,6,5,6,5) );
|
|||
|
case 2: return ( zip(13,11,24,23) );
|
|||
|
case 3: return ( zip(8,5,6,5) );
|
|||
|
case 4: return ( zip(13,9,24,23) );
|
|||
|
case 5: return ( zip(13,8,24,23) );
|
|||
|
case 6: return ( zip(13,7,8,7) );
|
|||
|
}
|
|||
|
break; }
|
|||
|
case 2: { switch (b) {
|
|||
|
case 2: return ( zoom(6,4,6,4,24,23,24,23) );
|
|||
|
case 3: return ( zip(13,11,13,10) );
|
|||
|
case 4: return ( zip(8,4,6,4) );
|
|||
|
case 5: return ( zip(13,8,13,11) );
|
|||
|
case 6: return ( zip(13,7,13,11) );
|
|||
|
}
|
|||
|
break; }
|
|||
|
case 3: { switch (b) {
|
|||
|
case 3: return ( zoom(13,10,13,10,10,7,10,7) );
|
|||
|
case 4: return ( zip(13,10,13,9) );
|
|||
|
case 5: return ( zip(13,8,8,5) );
|
|||
|
case 6: return ( zip(13,7,13,10) );
|
|||
|
}
|
|||
|
break; }
|
|||
|
case 4: { switch (b) {
|
|||
|
case 4: return ( zoom(13,9,13,9,9,5,9,5) );
|
|||
|
case 5: return ( zip(13,8,13,9) );
|
|||
|
case 6: return ( zip(13,7,13,9) );
|
|||
|
}
|
|||
|
break; }
|
|||
|
case 5: { switch (b) {
|
|||
|
case 5: return ( zoom(13,8,13,8,8,3,8,3) );
|
|||
|
case 6: return ( zip(13,7,13,8) );
|
|||
|
}
|
|||
|
break; }
|
|||
|
case 6: { return ( zoom(13,7,13,7,24,18,24,18) );
|
|||
|
break; }
|
|||
|
}
|
|||
|
|
|||
|
} /* end: book2 */
|
|||
|
|
|||
|
|
|||
|
/*====== MyMove ======*/
|
|||
|
|
|||
|
torve() {
|
|||
|
if ( makeprime() ) { /* this will use doubles, if it can */
|
|||
|
return;
|
|||
|
}
|
|||
|
else if ( walkingprime() ) { /* i have six prime points, so run!!! */
|
|||
|
return;
|
|||
|
}
|
|||
|
else if ( dice[0] == dice[1] ) { /* this is too easy! */
|
|||
|
if ( counterclock( kamikaze ) )
|
|||
|
return;
|
|||
|
if ( counterclock( dbuild ) ) /* claim new turf */
|
|||
|
return;
|
|||
|
if ( clockwise( run ) )
|
|||
|
return;
|
|||
|
}
|
|||
|
else if ( cleanup() ) { /* cover my single blot on prime points */
|
|||
|
return;
|
|||
|
}
|
|||
|
else if ( bearoff() ) { /* I'm ready, but you're in the back game! */
|
|||
|
if ( counterclock( gohome ) )
|
|||
|
return;
|
|||
|
if ( clockwise( run ) )
|
|||
|
return;
|
|||
|
}
|
|||
|
else {
|
|||
|
if ( clockwise( hitandrun ) )
|
|||
|
return;
|
|||
|
if ( matchup( natural ) )
|
|||
|
return;
|
|||
|
if ( clockwise( landonme ) )
|
|||
|
return;
|
|||
|
if ( counterclock( runnerup ) )
|
|||
|
return;
|
|||
|
if ( clockwise( scatter ) )
|
|||
|
return;
|
|||
|
if ( clockwise( run ) )
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
} /* end: torve */
|
|||
|
|
|||
|
|
|||
|
|
|||
|
villiers() {
|
|||
|
if ( makeprime() ) { /* this will use doubles, if it can */
|
|||
|
return;
|
|||
|
}
|
|||
|
else if ( walkingprime() ) { /* i have six prime points, so run!!! */
|
|||
|
return;
|
|||
|
}
|
|||
|
else if ( dice[0] == dice[1] ) { /* this is too easy! */
|
|||
|
if ( counterclock( kamikaze ) )
|
|||
|
return;
|
|||
|
if ( counterclock( dbuild ) ) /* claim new turf */
|
|||
|
return;
|
|||
|
if ( clockwise( run ) )
|
|||
|
return;
|
|||
|
}
|
|||
|
else if ( cleanup() ) { /* cover my single blot on prime points */
|
|||
|
return;
|
|||
|
}
|
|||
|
else if ( bearoff() ) { /* I'm ready, but you're in the back game! */
|
|||
|
if ( counterclock( gohome ) )
|
|||
|
return;
|
|||
|
if ( clockwise( run ) )
|
|||
|
return;
|
|||
|
}
|
|||
|
else {
|
|||
|
if ( clockwise( foolsdemise ) )
|
|||
|
return;
|
|||
|
if ( clockwise( idareyou ) )
|
|||
|
return;
|
|||
|
if ( counterclock( covermine ) )
|
|||
|
return;
|
|||
|
if ( matchup( natural ) )
|
|||
|
return;
|
|||
|
if ( clockwise( landonme ) )
|
|||
|
return;
|
|||
|
if ( clockwise( runnerup ) )
|
|||
|
return;
|
|||
|
if ( clockwise( scatter ) )
|
|||
|
return;
|
|||
|
if ( clockwise( run ) )
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
} /* end: villiers */
|
|||
|
|
|||
|
|
|||
|
|
|||
|
louisa() {
|
|||
|
if ( makeprime() ) { /* this will use doubles, if it can */
|
|||
|
return;
|
|||
|
}
|
|||
|
else if ( walkingprime() ) { /* i have six prime points, so run!!! */
|
|||
|
return;
|
|||
|
}
|
|||
|
else if ( dice[0] == dice[1] ) { /* this is too easy! */
|
|||
|
if ( counterclock( kamikaze ) )
|
|||
|
return;
|
|||
|
if ( counterclock( dbuild ) ) /* claim new turf */
|
|||
|
return;
|
|||
|
if ( clockwise( run ) )
|
|||
|
return;
|
|||
|
}
|
|||
|
else if ( cleanup() ) { /* cover my single blot on prime points */
|
|||
|
return;
|
|||
|
}
|
|||
|
else if ( bearoff() ) { /* I'm ready, but you're in the back game! */
|
|||
|
if ( counterclock( gohome ) )
|
|||
|
return;
|
|||
|
if ( clockwise( run ) )
|
|||
|
return;
|
|||
|
}
|
|||
|
else if ( (!naked() && goodboard()) || yourfolly() ) {
|
|||
|
if ( clockwise( hitandrun ) )
|
|||
|
return;
|
|||
|
if ( matchup( natural ) )
|
|||
|
return;
|
|||
|
if ( clockwise( landonme ) )
|
|||
|
return;
|
|||
|
if ( counterclock( runnerup ) )
|
|||
|
return;
|
|||
|
if ( clockwise( scatter ) )
|
|||
|
return;
|
|||
|
if ( clockwise( run ) )
|
|||
|
return;
|
|||
|
}
|
|||
|
else {
|
|||
|
if ( clockwise( foolsdemise ) )
|
|||
|
return;
|
|||
|
if ( clockwise( idareyou ) )
|
|||
|
return;
|
|||
|
if ( counterclock( covermine ) )
|
|||
|
return;
|
|||
|
if ( matchup( natural ) )
|
|||
|
return;
|
|||
|
if ( clockwise( landonme ) )
|
|||
|
return;
|
|||
|
if ( clockwise( runnerup ) )
|
|||
|
return;
|
|||
|
if ( clockwise( scatter ) )
|
|||
|
return;
|
|||
|
if ( clockwise( run ) )
|
|||
|
return;
|
|||
|
}
|
|||
|
} /* end: louisa */
|
|||
|
|
|||
|
|
|||
|
mymove() {
|
|||
|
int i, d;
|
|||
|
|
|||
|
if ( nomove() ) {
|
|||
|
if (lookforit && (dice[0] != dice[1])) {
|
|||
|
lookforit = FALSE;
|
|||
|
puts("\008... ");
|
|||
|
switch (level) {
|
|||
|
case 0: { puts("Blocked!"); break; }
|
|||
|
case 1: { puts("Well, no!"); break; }
|
|||
|
case 2: { puts("Thurb!"); break; }
|
|||
|
}
|
|||
|
sleep(10);
|
|||
|
restoreboard();
|
|||
|
update();
|
|||
|
|
|||
|
/* put the high die in list zero */
|
|||
|
d = dice[0]; dice[0] = dice[1]; dice[1] = d;
|
|||
|
|
|||
|
cantuse = ERROR; movesleft = 2; myturns = 1;
|
|||
|
switch (level) {
|
|||
|
case 0: { setchat("I move"); break; }
|
|||
|
case 1: { setchat("Let's try"); break; }
|
|||
|
case 2: { setchat("Move is"); break; }
|
|||
|
}
|
|||
|
debug(chatter);
|
|||
|
prmchk = 12;
|
|||
|
weasel();
|
|||
|
/* the rules say, use both dice if you can, or */
|
|||
|
/* the highest if one or the other but not both */
|
|||
|
}
|
|||
|
else {
|
|||
|
lookforit = TRUE;
|
|||
|
strcat(chatter," and now I'm blocked ");
|
|||
|
myturns = movesleft = 0;
|
|||
|
} }
|
|||
|
else if ( book() ) {
|
|||
|
return;
|
|||
|
}
|
|||
|
else if ( pending.flag ) {
|
|||
|
lurch( pending.fr, pending.to, 1 );
|
|||
|
clrpend();
|
|||
|
}
|
|||
|
else if ( endgame() ) { /* very solid tactics here!! */
|
|||
|
if ( clockwise( gohome ) )
|
|||
|
return;
|
|||
|
if ( clockwise( nobackgammon ) ) /* no excuse! */
|
|||
|
return;
|
|||
|
if ( clockwise( crosstable ) )
|
|||
|
return;
|
|||
|
if ( clockwise( fiftytworule ) )
|
|||
|
return;
|
|||
|
if ( clockwise( scatter ) )
|
|||
|
return;
|
|||
|
if ( clockwise( run ) )
|
|||
|
return;
|
|||
|
}
|
|||
|
else if ( point[ MYBAR ].stones > 0 ) { /* I'm on the bar! */
|
|||
|
if ( clockwise( hitandrun ) ) /* wreak havoc, please */
|
|||
|
return;
|
|||
|
if ( clockwise( run ) ) /* note: uses low die first */
|
|||
|
return;
|
|||
|
}
|
|||
|
else switch (level) {
|
|||
|
case 0: { villiers(); break; }
|
|||
|
case 1: { louisa(); break; }
|
|||
|
case 2: { torve(); break; }
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
} /* end: mymove */
|
|||
|
|
|||
|
/*------------------------------*/
|
|||
|
/* end of the GAMEPLAN.C module */
|
|||
|
/*------------------------------*/
|
|||
|
|