home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
vol_200
/
240_01
/
bg2.c
< prev
next >
Wrap
Text File
|
1987-07-30
|
40KB
|
1,538 lines
/*
** bg2.c -- initialization; major utils: play, arrange, etc.
*/
#include "backgmmn.h"
/*==========================================================================
INITIALIZATION and NEWBOARD commands -- start of a new game, or cold
===========================================================================*/
static char *getAtkn() {
if (tokenstyle) return( get5tkn() );
else return( get1tkn() );
}
static char *getBtkn() {
if (tokenstyle) return( get6tkn() );
else return( get2tkn() );
}
static char *getCtkn() {
if (tokenstyle) return( get7tkn() );
else return( get3tkn() );
}
static char *getDtkn() {
if (tokenstyle) return( get8tkn() );
else return( get4tkn() );
}
static wipeout() {
static int i;
player = 0;
barcube();
for (i = 0; i < 28; i++) {
point[i].stones = point[i].owner = 0;
}
update();
} /* end: wipeout */
setup() {
static int i, j, k; char *copyright;
myscore = yrscore = player = dice[0] = dice[1] = 0;
tokenstyle = swapped = tswap =
expert = helpdisabled = yrdice = FALSE;
show = moremsgline = tone = TRUE;
/* please be sure that main has called vid_init()...!!! */
off_cursor();
title();
token1 = getAtkn();
token2 = getBtkn();
copyright = backtalk[ MYLEVEL + 1 ];
draw_board( copyright );
for (i = 0; i < 28; i++) {
point[i].stones = point[i].owner = 0;
point[i].x = point[i].y = point[i].lastx = point[i].lasty = 0;
point[i].cx = point[i].cy = 0;
}
k = 68;
for (i = 1; i < 13; i++ ) { /* establish xy coords for the points */
j = 25 - i;
point[i].cx = point[j].cx = point[i].x = point[j].x = k;
k -= 5;
point[i].y = 4;
point[j].y = 18;
point[i].cy = 2;
point[j].cy = 20;
if (k == 38) k -= 5; /* skip over bar */
}
point[MYBAR].x = point[YRBAR].x = 38;
point[MYHOME].x = point[YRHOME].x = 75;
point[MYBAR].y = point[MYHOME].y = 5;
point[YRBAR].y = point[YRHOME].y = 17;
} /* end: setup */
newboard() {
static int i;
startcubevalue = 1;
wipedice(); wipeout();
putstone( MYHOME, 15, ME );
putstone( YRHOME, 15, YU );
putstone( YRHOME, 13, YU );
putstone( 1, 2, YU );
putstone( YRHOME, 8, YU );
putstone( 12, 5, YU );
putstone( YRHOME, 5, YU );
putstone( 17, 3, YU );
putstone( YRHOME, 0, 0 );
putstone( 19, 5, YU );
putstone( MYHOME, 10, ME );
putstone( 6, 5, ME );
putstone( MYHOME, 7, ME );
putstone( 8, 3, ME );
putstone( MYHOME, 2, ME );
putstone( 13, 5, ME );
putstone( MYHOME, 0, 0 );
putstone( 24, 2, ME );
} /* end: newboard */
void draw_board( c ) char *c; {
static int line,k;
static char *m = " ", *picture[] = {
"The Peelgrunt Game of GAMMON IV%s",
/* nice ain't it? */
"╔╤═══════════════════════════════╕o╒═══════════════════════════════╤╗",
"║│ ░░ ▓▓ ░░ ▓▓ ░░ ▓▓ │║│ ░░ ▓▓ ░░ ▓▓ ░░ ▓▓ │║",
"║│ │║│ │║",
"║│ ▓▓ ░░ ▓▓ ░░ ▓▓ ░░ │║│ ▓▓ ░░ ▓▓ ░░ ▓▓ ░░ │║",
"╚╧═══════════════════════════════╛o╘═══════════════════════════════╧╝"
};
clr_screen();
off_cursor();
msg(5,23, c );
off_cursor();
line = 0;
gotoxy(0,line++); wprintf(m); wprintf(picture[0],bgversion);
line = 3;
gotoxy(0,line++); wprintf(m); wprintf(picture[1]);
for (k = 0; k < 6; k++) {
gotoxy( 0,line++ ); wprintf(m); wprintf(picture[2]);
}
gotoxy(0,line++); wprintf(m); wprintf(picture[3]);
gotoxy(0,line++); wprintf(m); wprintf(picture[3]);
gotoxy(0,line++); wprintf(m); wprintf(picture[3]);
for (k = 0; k < 6; k++) {
gotoxy( 0,line++ ); wprintf(m); wprintf(picture[4]);
}
gotoxy(0,line); wprintf(m); wprintf(picture[5]);
} /* end: draw_board */
/*=========================================================================
DICE Commands: How to roll the dice
===========================================================================*/
haltgame() {
player = -1; /* if play resumes, ask whose roll it is */
msg(5,22,"Ok.");
jumpjack();
} /* end: haltgame */
static dpeek() {
if (yrdice) return; /* you know your own dice, probably...? */
if (expert) msg(5,22,"");
else msg(5,22,"The Dice will Rattle until you Roll. Now on ");
getdice();
wprintf("[%d] [%d] ...",dice[0],dice[1]);
} /* end: dpeek */
static getonedie() {
return ( (abs(acg()) % 6) + 1 );
} /* end: getonedie */
static fixup() { /* ensure that the low die is in dice[0] */
int d,e;
if (player == 0) return; /* whofirst? don't mess with the odds */
d = min(dice[0],dice[1]);
e = max(dice[0],dice[1]);
dice[0] = d;
dice[1] = e;
} /* end: fixup */
static getdice() {
int ch;
/* if it's MY dice we're using, generate random dice... */
if (!yrdice) {
dice[0] = getonedie();
acg(); /* bounce a little for luck */
dice[1] = getonedie();
}
/* but if it's YOUR dice, then get roll from user's real dice... */
else do
{
msg(5,23,"<> ");
wprintf( "%s roll: ", ((player == ME)? "My": "Your"));
if (!expert) wprintf("\b\b, using your dice: ");
wprintf(" First? ");
ch = keyin( acg );
if (ch == 27) haltgame();
ch -= '0';
if (ch < 1 || ch > 6) continue;
wink( ch + '0');
dice[0] = ch;
wprintf(" Second? ");
ch = keyin( acg );
if (ch == 27) haltgame();
ch -= '0';
if (ch < 1 || ch > 6) continue;
wink( ch + '0');
dice[1] = ch;
wprintf(" All Ok? ");
ch = keyin( acg );
ch = toupper( ch );
if (ch == 27) haltgame();
} while ( ch != 'Y' && ch != '\015' );
fixup();
} /* end: getdice */
static rolldice( who ) int who; {
int waiting,ch;
setchat("You Roll: ");
if (!expert) {
if (!yrdice) strcat(chatter," ^φP^eek,");
strcat(chatter," ^φD^ouble, ^φQ^uit, or <^φAnyKey^> to Roll ");
}
if (player == YU) { /* not executed if player == 0, i.e., whofirst */
waiting = TRUE;
while (waiting) {
msg(5,23,chatter);
ch = keyin(acg);
ch = toupper(ch);
switch ( ch ) {
case 27 : { haltgame(); break; }
case -69: /* F1 */
case 'P': { dpeek(); break; }
case -68: /* F2 */
case 'D': { udouble(); break; }
case -60: /* F10 */
case 'Q': { winner(ME,topstone(YU)); break; }
default : waiting = FALSE;
} }
off_cursor(); msg(5,22,""); msg(5,23,"");
}
highroller(who);
} /* end: rolldice */
static highroller( who ) int who; { /* parameter is not redundant */
static int y = 11;
static int xme, xyu;
/* get the values for two dice, either yours or mine */
getdice();
/* display the values of the dice in the board area */
off_cursor();
xme = 47; xyu = 12; /* decide which half to show the values in */
if (point[1].x > 40) {
xme = 12;
xyu = 47;
}
if (player) {
gotoxy(xyu,y); blanks(18); /* erase, if not whofirst */
gotoxy(xme,y); blanks(18);
}
if (who == ME) {
gotoxy(xme,y); wprintf("My");
}
else {
gotoxy(xyu,y); wprintf("Your");
}
wprintf(" Roll> [%d] ",dice[0]);
if (player) wprintf("[%d] ",dice[1]); /* whofirst doesn't show this */
} /* end: highroller */
/*========================================================================
MAJOR UTILITIES -- Miscellaneous functions sans which the game will not
proceed so well as otherwise..........
========================================================================*/
jumpjack()
{
longjmp( mark, -1 );
}
static saveboard() {
int i;
for (i = 0; i < 28; i++) {
bdsave[i].stones = point[i].stones;
bdsave[i].owner = point[i].owner;
}
} /* end: saveboard */
void restoreboard() {
int i;
for (i = 0; i < 28; i++) {
point[i].stones = bdsave[i].stones;
point[i].owner = bdsave[i].owner;
}
} /* end: restoreboard */
swaptokens() {
char *temp;
swapped ^= TRUE;
if (swapped) {
temp = token1;
token1 = token2;
token2 = temp;
}
else {
tswap ^= TRUE;
if (tswap) {
token1 = getCtkn();
token2 = getDtkn();
}
else {
token1 = getAtkn();
token2 = getBtkn();
}
}
} /* end: swaptokens */
static nxtyp(i) int i; {
if (i > 9) return ( i - 1 ); else return ( i + 1 );
}
static isbar(p) int p; {
return (( p == MYBAR ) || ( p == YRBAR ));
}
static ishome(p) int p; {
return (( p == MYHOME ) || ( p == YRHOME ));
}
static putstone( pt, cnt, color ) int pt, cnt, color; {
int i, xp, yp, slack;
char *background, *token;
if (cnt < 1) { /* empty point has neither stones nor owner */
cnt = 0;
color = 0;
}
point[pt].stones = cnt; /* number of stones on this point */
point[pt].owner = color; /* and whose they are */
/* stack stones 5 high in the home tray, 6 high on the points */
if (isbar(pt) || ishome(pt)) slack = 5; else slack = 6;
/* locate the base address of the point for animation */
xp = point[pt].x;
yp = point[pt].y;
/* decide on the background pattern to be used for empty places */
if (pt > 12) background = "▓▓ "; /* was "/\\ "; */
else background = "▓▓ "; /* was "\\/ "; */
if (point[1].x < 40) {
if ((pt % 2) == 1) background = "░░ "; /* was ".. "; */
}
else if ((pt % 2) == 0) background = "░░ "; /* was ".. "; */
if (ishome(pt)) background = " ";
if (isbar(pt)) background = "│║│ ";
/* get the token pattern to be used */
if (color == ME) {
token = token1;
}
else {
token = token2;
}
/* draw the entire point with token and background patterns */
off_cursor();
/* first erase all blots from this point (draw the background) */
for (i = 0; i < slack; i++) {
gotoxy(xp,yp);
wprintf(background); /* string has point's width */
point[pt].lastx = 0; /* future, not implemented */
point[pt].lasty = 0;
yp = nxtyp(yp);
}
/* now draw all the blots there are on this point onto the point */
for (i = 0; i < cnt; i++) {
xp = point[pt].x + (i / slack);
if ((i % slack) == 0) yp = point[pt].y;
gotoxy(xp, yp);
wprintf(token);
point[pt].lastx = xp; /* future, not implemented */
point[pt].lasty = yp;
yp = nxtyp(yp);
}
} /* end: putstone */
static hitblot( from, color ) int from, color; {
static int barpt, addone;
if (tone) beep();
barpt = whosebar( color );
putstone(from, 0, 0);
addone = point[barpt].stones + 1;
putstone( barpt, addone, color );
} /* end: hitblot */
static movestone( from, to) int from, to; {
static int opponent, subone, addone;
opponent = other( player );
if (point[to].owner == opponent) hitblot(to, opponent);
subone = point[from].stones - 1;
addone = point[to].stones + 1;
putstone(from, subone, player);
putstone(to, addone, player);
--movesleft;
checkwin(); /* never but NEVER let a win go unnoticed! */
} /* end: movestone */
/*========================================================================
CUBE Commands -- commands related to the cube, doubling, etc.
=========================================================================*/
static notyrcube() {
gotoxy(75,19); blanks(5);
gotoxy(75,20); blanks(5);
} /* end: notyrcube */
static notmycube() {
gotoxy(75,2); blanks(5);
gotoxy(75,3); blanks(5);
} /* end: notmycube */
static barcube() {
/* startcubevalue is normally 1, but it may have doubled */
/* if the opening rolloff for first turn came up doubles */
doubles.cube = startcubevalue;
doubles.whosecube = 0;
notmycube(); notyrcube();
gotoxy(37,11);
if (startcubevalue == 1) wprintf("[BAR]");
else if (doubles.cube < 16) wprintf("[ %d ]",doubles.cube);
else wprintf("[%03d]",doubles.cube);
} /* end: barcube */
static notbarcube() {
gotoxy(37,11); wprintf("^2 BAR ^");
} /* end: notbarcube */
static mycube(value) int value; {
notbarcube(); gotoxy(75,2); wprintf("^3CUBE^");
gotoxy(75,3);
sprintf(buzzard,"[%d]",value);
wprintf("%-5s",buzzard);
doubles.whosecube = ME;
} /* end: mycube */
static yrcube(value) int value; {
notbarcube; gotoxy(75,19); wprintf("^3CUBE^");
gotoxy(75,20); sprintf(buzzard,"[%d]",value);
wprintf("%-5s",buzzard);
doubles.whosecube = YU;
} /* end: yrcube */
static idouble() {
static int ch;
if (doubles.whosecube == YU || doubles.cube >= 256) {
; /* not mine, or not polite, so do nothing */
}
else {
notbarcube();
if (tone) beep();
msg(5,22,"^φI double. Will you accept the cube ");
wprintf("at %d points? ^",doubles.cube * 2);
do
{
ch = keyin( acg );
ch = toupper( ch );
if (ch == 27) winner(ME,0); /* Ha, fooled you! */
}
while ( ch != 'Y' && ch != 'N' ); /* only Y or N this time */
if (ch == 'Y') {
notmycube();
doubles.cube *= 2;
yrcube(doubles.cube);
off_cursor();
}
else winner(ME,0);
}
} /* end: idouble() */
static backgame() {
int imax, barred, count, i;
if (topstone(YU) < 12 && topstone(ME) > 18) {
if (mytotal() < yrtotal() + 4) return (TRUE);
imax = barred = count = 0;
i = 24;
while (i > 18) {
if (point[i].owner == ME) {
imax = i;
if (point[i].stones > 1) barred++;
count += point[i].stones;
}
i--;
}
return ((imax < topstone(YU) + 1) && (barred > 1 && count < 7));
}
else return ( mytotal() < yrtotal() + 24 );
} /* end: backgame */
static cubeval() {
int ineed, yuneed, yrtop, mytop;
if (endgame()) {
/* calculate the number of dice that are required to end */
/* the game, with appropriate fudge factors for position */
yrtop = topstone(YU);
mytop = topstone(ME);
ineed = 15 - point[MYHOME].stones;
yuneed = 15 - point[YRHOME].stones;
if (yrtop < 4 && yuneed < 3) return (FALSE); /* obvious */
/* topstones still running? use a different method */
if (mytop > 6 || yrtop > 6) {
ineed = 2 * (mytotal() / 8) + 1; /* number of dice */
yuneed = 2 * (yrtotal() / 8) + 1;
}
/* count the stones on point 6 twice, they're losers */
yuneed += point[6].stones;
ineed += point[6].stones;
/* you doubled, so you have the roll */
yuneed -= 2;
/* odd number left? */
if (ineed % 2) ineed++;
if (yuneed % 2) yuneed++;
/* is the one point empty? */
if (ineed > 4 && mytop > 3 && point[24].stones == 0) ineed++;
if (yuneed > 4 && yrtop > 3 && point[ 1].stones == 0) yuneed++;
if (mytop < yrtop && ineed < yuneed) return (TRUE);
if (yrtop < 5 && yuneed < ineed) return (FALSE);
return ( yuneed >= ineed );
}
else return ( backgame() );
} /* end: cubeval */
static testcube() {
if (cubeval()) {
msg(5,22,"I accept the cube.");
notyrcube();
doubles.cube *= 2;
mycube(doubles.cube);
}
else winner(YU,0);
} /* end: testcube */
static udouble() {
if (doubles.whosecube == ME) {
if (tone) beep();
msg(5,22,"It's MY cube, dummy!");
}
else testcube();
} /* end: udouble */
/*======================================================================
ARRANGE Command: Move stones around in the playing area. Play will
commence with this final arrangement. Notice, this
command allows for cheating because the line input
function traps Ctrl-C and executes jumpjack(). Player
returns to the command line with the game frozen, may
re-arrange as desired, then resume play.
========================================================================*/
arrange() { /* update() must follow arrangement */
if ( setjmp( mark ) != 0 ) update();
else
{
moveabout(); /* infinite loop */
}
} /* end: arrange */
static moveabout() {
player = -1; /* flag to ask who moves first */
if (!expert)
msg(5,22,"Type BAR or HOME, or the Number of a Point.");
while ( TRUE ) { /* exit via jumpjack() by typing ESCape */
mytotal();
yrtotal();
revise();
}
} /* end: moveabout */
static getpt(b,h) int b,h; {
static char ans[6], *p; int x, d1, d2, look, try;
static char *cusswords = "?!LP .,-@#$%^&*()CDFGIJKNPQSTUVWXYZ";
/* not HOME or BAR */
on_cursor();
getms( ans, 5, acg, haltgame);
p = ans;
while (*p) { *p = toupper(*p); p++; }
off_cursor();
if (!helpdisabled && (contains(ans,cusswords) == TRUE)) {
x = ERROR;
msg(5,23,"");
if (point[ whosebar(player) ].stones > 0) {
wprintf("You're on the Bar, so let's move that one! ^3BAR^ ");
x = b;
}
else {
wprintf("Are you ");
if (cantuse != 0 && cantuse != 1) wprintf("REALLY ");
wprintf("blocked? Try moving From ");
look = 24;
while (look > 0) {
try = list[0][look];
if (try == ERROR) try = list[1][look];
if ( try != ERROR ) {
wprintf("%d To ",25-look);
if (try == YRHOME) wprintf("HOME");
else wprintf("%d",25-try);
look = 0;
}
look--;
}
sleep(1);
}
}
else if (contains(ans,"B") == TRUE) x = b;
else if (contains(ans,"H") == TRUE) x = h;
else {
x = atoi( ans );
if (x < 1 || x > 24) x = ERROR;
else x = 25 - x; /* translate human to computer view */
}
return (x);
} /* end: getpt */
static whoseit(p,a,b) char *p; int a,b; {
int ch;
if (point[a].stones > 0 && point[b].stones > 0) {
msg(5,22,"Whose "); wprintf(p); wprintf("? 1 = ");
wprintf(token1);
wprintf(" 2 = "); wprintf(token2); wprintf(" ");
loo: ch = keyin( acg );
if (!(ch == '1' || ch == '2')) goto loo;
msg(5,22,"From ");
if (ch == '1') { ch = a; wprintf(token1); }
else { wprintf(token2); ch = b; }
wprintf("'s "); wprintf(p);
return ( ch );
}
else if (point[a].stones > 0) return (a);
else if (point[b].stones > 0) return (b);
else return (ERROR);
} /* end: whoseit */
static revise() {
do {
setchat("Move a Stone From? ");
msg(5,23,chatter);
}
while ( !delightful() );
} /* end: revise */
static delightful() {
static int from, to, fcnt, tcnt, fcolor, tcolor;
from = getpt(MYBAR,MYHOME);
sprintf(buzzard,"%d",abs(25 - from));
if (from == MYBAR) {
from = whoseit("bar",MYBAR,YRBAR);
strcpy(buzzard,"BAR");
}
if (from == MYHOME) {
from = whoseit("home",MYHOME,YRHOME);
strcpy(buzzard,"HOME");
}
if (from == ERROR) {
msg(5,22,"Hit ESC to quit.");
return( FALSE );
}
/*-----------------------------------------------------*/
/* establish the color of the stones on the from point */
/*-----------------------------------------------------*/
fcolor = point[from].owner;
/*--------------------------------------------------*/
/* establish the number of stones on the from point */
/*--------------------------------------------------*/
fcnt = point[from].stones;
if (fcnt == 0) {
msg(5,22,"What's the point?");
return(FALSE);
}
strcat(chatter,buzzard); /* this avoids use of save_cursor() */
strcat(chatter," To? ");
msg(5,23,chatter);
to = getpt(MYBAR,MYHOME);
sprintf(buzzard,"%d",abs(25 - to));
if (to == MYBAR) {
if (fcolor == YU) to = YRBAR;
strcpy(buzzard,"BAR");
}
if (to == MYHOME) {
if (fcolor == YU) to = YRHOME;
strcpy(buzzard,"HOME");
}
if (to == ERROR) {
msg(5,22,"Hit ESC to quit.");
return(FALSE);
}
if (from == to) {
msg(5,22,"Quite easily done!");
return(FALSE);
}
strcat(chatter,buzzard);
/*---------------------------------------------------*/
/* establish the color of the stones on the to point */
/*---------------------------------------------------*/
tcolor = point[to].owner;
/*------------------------------------------------*/
/* establish the number of stones on the to point */
/*------------------------------------------------*/
tcnt = point[to].stones;
if (fcolor == tcolor || tcolor == 0) {
msg(5,23,chatter);
--fcnt;
++tcnt;
putstone(from, fcnt, fcolor); /* one less */
putstone(to, tcnt, fcolor); /* one more */
msg(5,22,"");
return (TRUE);
}
else {
msg(5,22,"Evict the other stone");
if (tcnt > 1) wprintf("s");
wprintf(" first!");
return (FALSE);
}
} /* end: delightful */
/*=======================================================================
PLAY Command - this is the command that initiates the 2-player game
=========================================================================*/
play() {
if ( setjmp( mark ) != 0 ) return;
else
{
whofirst();
taketurns(); /* infinite loop here */
}
} /* end: play */
static whofirst() {
int ch, myval, yrval;
if (yrdice || (player < 0)) { /* board has been re-arranged */
msg(5,23,"Is it my "); wprintf(token1);
wprintf(" turn or your "); wprintf(token2);
wprintf(" turn? ");
loo: ch = keyin( acg );
ch = toupper(ch);
if (!(ch == 'M' || ch == 'Y')) goto loo;
if (ch == 'M') player = YU; /* player says Me, of course! */
else player = ME;
rolldice(player);
}
else if (player == 0) { /* fresh start, roll the dice */
barcube();
zoo: msg(5,22,"Tossing for first turn...");
wipedice();
rolldice(ME);
myval = dice[0];
rolldice(YU);
yrval = dice[0];
if (myval == yrval) {
if (tone) beep();
off_cursor();
gotoxy(37,11); wprintf("[^4 ^]"); sleep(1);
startcubevalue *= 2;
if (startcubevalue > 8) startcubevalue = 8;
doubles.cube = startcubevalue;
gotoxy(37,11);
if (doubles.cube < 16) wprintf("[ %d ]",doubles.cube);
else wprintf("[%03d]",doubles.cube);
if (startcubevalue < 9) {
msg(5,23,"Double the cube!");
sleep(1);
}
goto zoo;
}
else if (myval < yrval) player = YU;
else player = ME;
dice[0] = max(myval,yrval); dice[1] = min(myval,yrval);
}
/* otherwise, continue with last dice rolled as play is resumed */
} /* end: whofirst */
static getmove() {
static int i, ch, temp, happy;
cantuse = ERROR; /* important for human player in tellmove */
movesleft = 2;
if (dice[0] == dice[1]) movesleft += 2;
temp = movesleft;
getlist(); saveboard(); lookforit = TRUE;
if ( nomove() ) {
msg(5,22,"All ");
if (player == ME) wprintf("my"); else wprintf("your");
wprintf(" moves are blocked!");
if (player == YU) sleep(1);
return;
}
if (player == ME) {
/* handle doubles as two consecutive, independent moves */
setchat("I move");
msg(5,22,chatter);
if (movesleft == 4) myturns = 2; else myturns = 1;
clrpend();
while (myturns > 0) {
cantuse = ERROR;
movesleft = 2;
while (movesleft > 0) { getlist(); mymove(); }
myturns--;
}
msg(5,22,chatter);
wputs("\b.");
}
else { /* allow the human to take back a bad board position */
happy = FALSE;
while (!happy) {
while (movesleft > 0) { getlist(); yrmove(); }
msg(5,23,"All ok? Y/N ");
do {
ch = keyin( acg );
ch = toupper(ch);
} while (ch != 'N' && (ch != 'Y' && ch != '\015'));
if ( ch == 'N' ) {
msg(5,23,"Ok, as it was...");
restoreboard();
update();
movesleft = temp;
cantuse = ERROR;
}
else happy = TRUE;
msg(5,22,"");
}
}
} /* end: getmove */
static taketurns() { /* COMPUTER CUBE STRATEGY IS HERE */
while (TRUE) { /* NO EXIT! Only a Win or player ESC can exit */
getmove();
player = other(player);
if ( player == ME ) {
if ( endgame() ) {
if (topstone(ME) < 6 && cubeval()) idouble();
else if ( mytotal() < (yrtotal() - 8) ) {
idouble();
}
}
else if ( bearoff() ) idouble();
}
rolldice (player);
}
} /* end: taketurns */
endgame() { /* Is no strategy required from here on in? */
return ( (25 - topstone(YU)) > topstone(ME) );
} /* end: endgame */
bearoff() {
return (topstone(ME) < 7);
} /* end: bearoff */
void clrpend() {
pending.flag = FALSE;
} /* end: clrpend */
/*=============================================*/
/* Y O U R M O V E */
/*=============================================*/
static tellmove() { /* show what the player's current dice are */
int k,n;
n = movesleft;
msg(5,22,"You ");
if (!expert) { wprintf(token2); wprintf(" "); }
wprintf("have ");
while (n--) {
if (dice[0] == dice[1]) k = dice[0]; /* doubles? */
else if (cantuse == 1) k = dice[0];
else if (cantuse == 0) k = dice[1];
else if (n == 1) k = dice[1]; /* 2 of 2? */
else k = dice[0]; /* 1 of 2? */
wprintf("[%d] ",k);
}
wprintf("left");
if (expert) wprintf("."); else wprintf(", moving from high to low.");
} /* end: tellmove */
static yrmove() {
if ( nomove() ) {
msg(5,22,"You have no more moves in this line of play.");
movesleft = 0;
return;
}
else {
loo: tellmove();
if (!getyrmove()) {
hint();
goto loo;
}
msg(5,22,"");
}
} /* end: yrmove */
hint() {
if (!expert) {
msg(5,22,"HELP, BAR and HOME are useful words in this game.");
sleep(1);
}
} /* end: hint */
nomove() {
int i,j;
for (i = 0; i < 2; i++)
for (j = 0; j < 28; j++)
if (list[i][j] != ERROR) return (FALSE);
return (TRUE);
} /* end: nomove */
static getyrmove() {
int fpoint, tpoint;
firstmove = FALSE; /* I got it, I got it! */
msg(5,23,"Move from? ");
fpoint = getpt(YRBAR,YRHOME);
if ( fpoint == ERROR ||
(list[0][fpoint] == ERROR && list[1][fpoint] == ERROR)) {
return (FALSE);
}
wprintf(" To? ");
tpoint = getpt(YRBAR,YRHOME);
if ( tpoint == ERROR ||
(list[0][fpoint] != tpoint && list[1][fpoint] != tpoint)) {
return (FALSE);
}
HIclack(); movestone( fpoint, tpoint ); LOclack();
if (movesleft < 2) {
if (list[0][fpoint] == tpoint) cantuse = 0;
else cantuse = 1;
}
return (TRUE);
} /* end: getyrmove */
/*====== Functions That Make The Selected Move ======*/
void setchat( p ) char *p; {
strcpy(chatter,p);
} /* end: setchat */
static putdice( f,t) int f,t; {
static char q[15];
if (t == MYHOME) sprintf(q," %d to Home,",25 - f);
else if (f == MYBAR) sprintf(q," Bar to %d,",25 - t);
else sprintf(q," %d to %d,",25 - f, 25 - t);
strcat(chatter,q);
msg(5,22,chatter); /* avoid using save_cursor() */
} /* end: putdice */
lurch( f, t, zlist ) int f, t, zlist; {
LOclack();
movestone( f, t ); /* move the stone */
HIclack();
putdice(f,t); /* tell user, the action is a bit fast */
if (movesleft < 2) cantuse = zlist;
} /* end: lurch */
/*==========================================================================
GETLIST -- Find the possible moves for any particular throw of the dice
===========================================================================*/
static checkpips( whichlist, ptimon, pips, tops )
int whichlist, ptimon, pips, tops; {
static int j,k;
if ( !ptimon ) {
j = whosebar(player); /* 0 if you, 25 if me */
k = abs(j - pips);
}
else if (player == ME) {
j = ptimon;
k = j - pips;
if (k < 1) k = MYHOME;
}
else {
j = 25 - ptimon;
k = j + pips;
if (k > 24) k = YRHOME;
}
if (point[j].stones > 0 && point[j].owner == player) {
/* no move to a blocked point */
if (point[k].owner != player && point[k].stones > 1)
return;
/* no move home if i can't bear off yet */
if (k == whosehome(player) && cantbearoff(j,pips,tops))
return;
/* no other move is allowed if i'm on the bar */
if (tops == 25 && j != whosebar(player))
return;
/* the move is legal (but maybe not optimal) */
list [whichlist] [j] = k;
}
} /* end: checkpips */
static build( whichlist, pips ) int whichlist, pips; {
int i, tops;
if (whichlist == cantuse) return;
tops = topstone(player);
for (i = 0; i < 26; i++) checkpips( whichlist, i, pips, tops );
} /* end: build */
static getlist() { /* find all legal moves using these dice */
static int i, j;
for (i = 0; i < 2; i++) /* initialize the lists */
for (j = 0; j < 28; j++)
list [i] [j] = ERROR;
build( 0, dice[0] ); /* usually the low die */
build( 1, dice[1] ); /* usually the high die */
} /* end: getlist */
/*==========================================================================
EVALUATE UTILITIES -- Functions for legal and/or best play, telling who's
who, who's ahead, who won, etc. etc.
============================================================================*/
mytotal() {
int i, cnt;
cnt = 0;
for (i = 0; i < 26; i++) {
if (point[i].owner == ME) cnt += point[i].stones * i;
}
if (show) {
gotoxy(0,3); wprintf("^0%03d",cnt);
}
return (cnt);
} /* end: mytotal */
yrtotal() {
int i, cnt;
cnt = 0;
for (i = 0; i < 26; i++) {
if (point[i].owner == YU) cnt += point[i].stones * (25 - i);
}
if (show) {
gotoxy(0,19); wprintf("^0%03d",cnt);
}
return (cnt);
} /* end: yrtotal */
topstone( who ) int who; {
static int i,j;
if (point[ whosebar( who ) ].stones > 0) i = 25;
else {
i = 24;
while (i > 0) {
if (who == ME) j = i; else j = 25 - i;
if (point[j].stones > 0 &&
point[j].owner == who) return (i);
--i;
}
}
return (i); /* return normalized value, 1 - 25, 0 is home */
} /* end: topstone */
static cantbearoff( mypt, pips, tops ) int mypt, pips, tops; {
/* My destination is Home, but can I do it??? */
if (mypt > 6) mypt = 25 - mypt; /* normalize inner table */
/* I can't bear off if there's anybody still not in my inner table */
if (tops > 6) return (TRUE);
/* If I'm the highest blot in my own table, I CAN bear off */
if (tops == mypt) return (FALSE);
/* If I'm NOT high, I have to have an exact roll to get away with it */
return ( (mypt != pips) );
} /* end: cantbearoff */
static whosebar( who ) int who; {
return ( (who == ME? MYBAR: YRBAR) );
}
static whosehome( who ) int who; {
return ( (who == YU? YRHOME: MYHOME) );
}
static checkwin() {
if (mytotal() == 0) winner(ME, topstone(YU));
if (yrtotal() == 0) winner(YU, topstone(ME));
} /* end: checkwin */
static other( color ) int color; {
if (color == ME) return (YU); else return (ME);
} /* end: otherplayer */
static winner( who, high ) int who, high; {
int gammon; char ch;
if (tone) beep();
if (point[ whosehome( other(who) )].stones > 0) gammon = 1;
else gammon = 2; /* nothing off is a gammon! */
if (high == 0) gammon = 1; /* someone doubled */
else if (high > 18) gammon = 3; /* backgammon! */
msg(5,22,"");
if (who == ME) wprintf("I"); else wprintf("You"); wprintf(" win");
switch (gammon) {
case 1: { wprintf("!"); break; }
case 2: { wprintf(" a Gammon!"); break; }
case 3: { wprintf(" a Backgammon!"); break; }
}
gammon *= doubles.cube;
switch (who) {
case ME: { myscore += gammon; break; }
case YU: { yrscore += gammon; break; }
}
putscore();
msg(5,23,"Hit ESC to resume play");
loo: ch = keyin( acg ); if (ch != 27) goto loo;
player = 0;
reverse(); deciding = FALSE; jumpjack();
} /* end: winner */
putscore() {
gotoxy(39,0); clreol(); gotoxy(53,0);
wprintf("SCORE: You %d, Me %d",yrscore,myscore);
} /* end: putscore */
/*========================================================================
REVERSE Command - allow player to take the opponent's viewpoint of the
board layout, mirror the board. Returns board layout
to the arranged position as seen from opposite side.
==========================================================================*/
reverse() {
int cnt1, cnt2, cnt3, cnt4;
off_cursor();
cnt1 = point[MYHOME].stones; /* save counts for erase */
cnt2 = point[YRHOME].stones;
cnt3 = point[MYBAR].stones;
cnt4 = point[YRBAR].stones;
putstone( MYHOME, 0, 0); /* erase old trays before update */
putstone( YRHOME, 0, 0);
halfswap(1); halfswap(13);
gotoxy(0,11); wprintf(" "); /* erase HOME message */
gotoxy(75,11); wprintf(" ");
if (point[1].x < 40) {
point[MYHOME].x = point[YRHOME].x = 0;
}
else {
point[MYHOME].x = point[YRHOME].x = 75;
}
point[MYHOME].owner = point[MYBAR].owner = ME; /* restore counts */
point[YRHOME].owner = point[YRBAR].owner = YU;
point[MYHOME].stones = cnt1;
point[YRHOME].stones = cnt2;
point[MYBAR].stones = cnt3;
point[YRBAR].stones = cnt4;
} /* end: reverse */
static
char *charm[] = {
"Gammon IV concept & text graphic rendition by David C. Oshel",
"MidSummer's Day, June 21, 1985",
"To Whomever Destroys This Notice -- Nothing Shall Happen, Forever"
};
static halfswap( n ) int n; {
static int i, j, k, o;
o = n + 6;
for (i = n; i < o; i++) {
j = ((o * 2) - 1) - i;
k = point[i].x;
point[i].cx = point[i].x = point[j].x;
point[j].cx = point[j].x = k;
}
} /* end: halfswap */
static wipedice() {
static char *s = " ";
off_cursor();
gotoxy(47,11); wprintf(s); /* erase dice roll messages */
gotoxy(12,11); wprintf(s);
} /* end: wipedice */
update() {
int i, x, c;
for (i = 1; i < 25; i++) {
gotoxy(point[i].cx,point[i].cy);
wprintf("%2d",25 - i);
}
if (doubles.whosecube == YU) yrcube(doubles.cube);
else if (doubles.whosecube == ME) mycube(doubles.cube);
else barcube();
for (i = 0; i < 28; i++) {
x = point[i].stones;
c = point[i].owner;
putstone(i,x,c);
}
if (point[1].x < 40) x = 0; else x = 75;
gotoxy(x,11); wprintf("HOME");
putscore(); mytotal(); yrtotal();
} /* end: update */
/* eof: bg2.c */