534 lines
12 KiB
C
534 lines
12 KiB
C
/* $NetBSD: main.c,v 1.21 2005/02/15 12:56:20 jsm 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 <sys/cdefs.h>
|
|
#ifndef lint
|
|
__COPYRIGHT("@(#) Copyright (c) 1980, 1993\n\
|
|
The Regents of the University of California. All rights reserved.\n");
|
|
#endif /* not lint */
|
|
|
|
#ifndef lint
|
|
#if 0
|
|
static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 5/31/93";
|
|
#else
|
|
__RCSID("$NetBSD: main.c,v 1.21 2005/02/15 12:56:20 jsm Exp $");
|
|
#endif
|
|
#endif /* not lint */
|
|
|
|
#include <time.h>
|
|
|
|
#include "back.h"
|
|
#include "backlocal.h"
|
|
|
|
#define MVPAUSE 5 /* time to sleep when stuck */
|
|
|
|
extern const char *const instr[]; /* text of instructions */
|
|
extern const char *const message[]; /* update message */
|
|
#ifndef NCURSES_VERSION
|
|
short ospeed; /* tty output speed */
|
|
#endif
|
|
|
|
const char *const helpm[] = { /* help message */
|
|
"Enter a space or newline to roll, or",
|
|
" R to reprint the board\tD to double",
|
|
" S to save the game\tQ to quit",
|
|
0
|
|
};
|
|
|
|
const char *const contin[] = { /* pause message */
|
|
"(Type a newline to continue.)",
|
|
"",
|
|
0
|
|
};
|
|
static const char rules[] = "\nDo you want the rules of the game?";
|
|
static const char noteach[] = "Teachgammon not available!\n\a";
|
|
static const char need[] = "Do you need instructions for this program?";
|
|
static const char askcol[] =
|
|
"Enter 'r' to play red, 'w' to play white, 'b' to play both:";
|
|
static const char rollr[] = "Red rolls a ";
|
|
static const char rollw[] = ". White rolls a ";
|
|
static const char rstart[] = ". Red starts.\n";
|
|
static const char wstart[] = ". White starts.\n";
|
|
static const char toobad1[] = "Too bad, ";
|
|
static const char unable[] = " is unable to use that roll.\n";
|
|
static const char toobad2[] = ". Too bad, ";
|
|
static const char cantmv[] = " can't move.\n";
|
|
static const char bgammon[] = "Backgammon! ";
|
|
static const char gammon[] = "Gammon! ";
|
|
static const char again[] = ".\nWould you like to play again?";
|
|
static const char svpromt[] = "Would you like to save this game?";
|
|
|
|
static const char password[] = "losfurng";
|
|
static char pbuf[10];
|
|
|
|
int
|
|
main(argc, argv)
|
|
int argc __attribute__((__unused__));
|
|
char **argv;
|
|
{
|
|
int i; /* non-descript index */
|
|
int l; /* non-descript index */
|
|
char c; /* non-descript character storage */
|
|
long t; /* time for random num generator */
|
|
|
|
/* revoke setgid privileges */
|
|
setregid(getgid(), getgid());
|
|
|
|
/* initialization */
|
|
bflag = 2; /* default no board */
|
|
signal(SIGINT, getout); /* trap interrupts */
|
|
if (tcgetattr(0, &old) == -1) /* get old tty mode */
|
|
errexit("backgammon(gtty)");
|
|
noech = old;
|
|
noech.c_lflag &= ~ECHO;
|
|
bg_raw = noech;
|
|
bg_raw.c_lflag &= ~ICANON; /* set up modes */
|
|
ospeed = cfgetospeed(&old); /* for termlib */
|
|
|
|
/* get terminal capabilities, and decide if it can cursor address */
|
|
tflag = getcaps(getenv("TERM"));
|
|
/* use whole screen for text */
|
|
if (tflag)
|
|
begscr = 0;
|
|
t = time(NULL);
|
|
srandom(t); /* 'random' seed */
|
|
|
|
#ifdef V7
|
|
while (*++argv != 0) /* process arguments */
|
|
#else
|
|
while (*++argv != -1) /* process arguments */
|
|
#endif
|
|
getarg(&argv);
|
|
args[acnt] = '\0';
|
|
if (tflag) { /* clear screen */
|
|
noech.c_oflag &= ~(ONLCR | OXTABS);
|
|
bg_raw.c_oflag &= ~(ONLCR | OXTABS);
|
|
clear();
|
|
}
|
|
fixtty(&bg_raw); /* go into raw mode */
|
|
|
|
/* check if restored game and save flag for later */
|
|
if ((rfl = rflag) != 0) {
|
|
text(message); /* print message */
|
|
text(contin);
|
|
wrboard(); /* print board */
|
|
/* if new game, pretend to be a non-restored game */
|
|
if (cturn == 0)
|
|
rflag = 0;
|
|
} else {
|
|
rscore = wscore = 0; /* zero score */
|
|
text(message); /* update message without pausing */
|
|
|
|
if (aflag) { /* print rules */
|
|
writel(rules);
|
|
if (yorn(0)) {
|
|
|
|
fixtty(&old); /* restore tty */
|
|
execl(TEACH, "teachgammon", args[1]?args:0,
|
|
(char *) 0);
|
|
|
|
tflag = 0; /* error! */
|
|
writel(noteach);
|
|
exit(1);
|
|
} else {/* if not rules, then instructions */
|
|
writel(need);
|
|
if (yorn(0)) { /* print instructions */
|
|
clear();
|
|
text(instr);
|
|
}
|
|
}
|
|
}
|
|
init(); /* initialize board */
|
|
|
|
if (pnum == 2) {/* ask for color(s) */
|
|
writec('\n');
|
|
writel(askcol);
|
|
while (pnum == 2) {
|
|
c = readc();
|
|
switch (c) {
|
|
|
|
case 'R': /* red */
|
|
pnum = -1;
|
|
break;
|
|
|
|
case 'W': /* white */
|
|
pnum = 1;
|
|
break;
|
|
|
|
case 'B': /* both */
|
|
pnum = 0;
|
|
break;
|
|
|
|
case 'P':
|
|
if (iroll)
|
|
break;
|
|
if (tflag)
|
|
curmove(curr, 0);
|
|
else
|
|
writec('\n');
|
|
writel("Password:");
|
|
signal(SIGALRM, getout);
|
|
cflag = 1;
|
|
alarm(10);
|
|
for (i = 0; i < 10; i++) {
|
|
pbuf[i] = readc();
|
|
if (pbuf[i] == '\n')
|
|
break;
|
|
}
|
|
if (i == 10)
|
|
while (readc() != '\n');
|
|
alarm(0);
|
|
cflag = 0;
|
|
if (i < 10)
|
|
pbuf[i] = '\0';
|
|
for (i = 0; i < 9; i++)
|
|
if (pbuf[i] != password[i])
|
|
getout(0);
|
|
iroll = 1;
|
|
if (tflag)
|
|
curmove(curr, 0);
|
|
else
|
|
writec('\n');
|
|
writel(askcol);
|
|
break;
|
|
|
|
default: /* error */
|
|
writec('\007');
|
|
}
|
|
}
|
|
} else
|
|
if (!aflag)
|
|
/* pause to read message */
|
|
text(contin);
|
|
|
|
wrboard(); /* print board */
|
|
|
|
if (tflag)
|
|
curmove(18, 0);
|
|
else
|
|
writec('\n');
|
|
}
|
|
/* limit text to bottom of screen */
|
|
if (tflag)
|
|
begscr = 17;
|
|
|
|
for (;;) { /* begin game! */
|
|
/* initial roll if needed */
|
|
if ((!rflag) || raflag)
|
|
roll();
|
|
|
|
/* perform ritual of first roll */
|
|
if (!rflag) {
|
|
if (tflag)
|
|
curmove(17, 0);
|
|
while (D0 == D1) /* no doubles */
|
|
roll();
|
|
|
|
/* print rolls */
|
|
writel(rollr);
|
|
writec(D0 + '0');
|
|
writel(rollw);
|
|
writec(D1 + '0');
|
|
|
|
/* winner goes first */
|
|
if (D0 > D1) {
|
|
writel(rstart);
|
|
cturn = 1;
|
|
} else {
|
|
writel(wstart);
|
|
cturn = -1;
|
|
}
|
|
}
|
|
/* initialize variables according to whose turn it is */
|
|
|
|
if (cturn == 1) { /* red */
|
|
home = 25;
|
|
bar = 0;
|
|
inptr = &in[1];
|
|
inopp = &in[0];
|
|
offptr = &off[1];
|
|
offopp = &off[0];
|
|
Colorptr = &color[1];
|
|
colorptr = &color[3];
|
|
colen = 3;
|
|
} else { /* white */
|
|
home = 0;
|
|
bar = 25;
|
|
inptr = &in[0];
|
|
inopp = &in[1];
|
|
offptr = &off[0];
|
|
offopp = &off[1];
|
|
Colorptr = &color[0];
|
|
colorptr = &color[2];
|
|
colen = 5;
|
|
}
|
|
|
|
/* do first move (special case) */
|
|
if (!(rflag && raflag)) {
|
|
if (cturn == pnum) /* computer's move */
|
|
move(0);
|
|
else { /* player's move */
|
|
mvlim = movallow();
|
|
/* reprint roll */
|
|
if (tflag)
|
|
curmove(cturn == -1 ? 18 : 19, 0);
|
|
proll();
|
|
getmove(); /* get player's move */
|
|
}
|
|
}
|
|
if (tflag) {
|
|
curmove(17, 0);
|
|
cline();
|
|
begscr = 18;
|
|
}
|
|
/* no longer any diff- erence between normal game and
|
|
* recovered game. */
|
|
rflag = 0;
|
|
|
|
/* move as long as it's someone's turn */
|
|
while (cturn == 1 || cturn == -1) {
|
|
|
|
/* board maintainence */
|
|
if (tflag)
|
|
refresh(); /* fix board */
|
|
else
|
|
/* redo board if -p */
|
|
if (cturn == bflag || bflag == 0)
|
|
wrboard();
|
|
|
|
/* do computer's move */
|
|
if (cturn == pnum) {
|
|
move(1);
|
|
|
|
/* see if double refused */
|
|
if (cturn == -2 || cturn == 2)
|
|
break;
|
|
|
|
/* check for winning move */
|
|
if (*offopp == 15) {
|
|
cturn *= -2;
|
|
break;
|
|
}
|
|
continue;
|
|
|
|
}
|
|
/* (player's move) */
|
|
|
|
/* clean screen if safe */
|
|
if (tflag && hflag) {
|
|
curmove(20, 0);
|
|
clend();
|
|
hflag = 1;
|
|
}
|
|
/* if allowed, give him a chance to double */
|
|
if (dlast != cturn && gvalue < 64) {
|
|
if (tflag)
|
|
curmove(cturn == -1 ? 18 : 19, 0);
|
|
writel(*Colorptr);
|
|
c = readc();
|
|
|
|
/* character cases */
|
|
switch (c) {
|
|
|
|
/* reprint board */
|
|
case 'R':
|
|
wrboard();
|
|
break;
|
|
|
|
/* save game */
|
|
case 'S':
|
|
raflag = 1;
|
|
save(1);
|
|
break;
|
|
|
|
/* quit */
|
|
case 'Q':
|
|
quit();
|
|
break;
|
|
|
|
/* double */
|
|
case 'D':
|
|
dble();
|
|
break;
|
|
|
|
/* roll */
|
|
case ' ':
|
|
case '\n':
|
|
roll();
|
|
writel(" rolls ");
|
|
writec(D0 + '0');
|
|
writec(' ');
|
|
writec(D1 + '0');
|
|
writel(". ");
|
|
|
|
/* see if he can move */
|
|
if ((mvlim = movallow()) == 0) {
|
|
|
|
/* can't move */
|
|
writel(toobad1);
|
|
writel(*colorptr);
|
|
writel(unable);
|
|
if (tflag) {
|
|
if (pnum) {
|
|
buflush();
|
|
sleep(MVPAUSE);
|
|
}
|
|
}
|
|
nexturn();
|
|
break;
|
|
}
|
|
/* get move */
|
|
getmove();
|
|
|
|
/* okay to clean screen */
|
|
hflag = 1;
|
|
break;
|
|
|
|
/* invalid character */
|
|
default:
|
|
|
|
/* print help message */
|
|
if (tflag)
|
|
curmove(20, 0);
|
|
else
|
|
writec('\n');
|
|
text(helpm);
|
|
if (tflag)
|
|
curmove(cturn == -1 ? 18 : 19, 0);
|
|
else
|
|
writec('\n');
|
|
|
|
/* don't erase */
|
|
hflag = 0;
|
|
}
|
|
} else {/* couldn't double */
|
|
|
|
/* print roll */
|
|
roll();
|
|
if (tflag)
|
|
curmove(cturn == -1 ? 18 : 19, 0);
|
|
proll();
|
|
|
|
/* can he move? */
|
|
if ((mvlim = movallow()) == 0) {
|
|
|
|
/* he can't */
|
|
writel(toobad2);
|
|
writel(*colorptr);
|
|
writel(cantmv);
|
|
buflush();
|
|
sleep(MVPAUSE);
|
|
nexturn();
|
|
continue;
|
|
}
|
|
/* get move */
|
|
getmove();
|
|
}
|
|
}
|
|
|
|
/* don't worry about who won if quit */
|
|
if (cturn == 0)
|
|
break;
|
|
|
|
/* fix cturn = winner */
|
|
cturn /= -2;
|
|
|
|
/* final board pos. */
|
|
if (tflag)
|
|
refresh();
|
|
|
|
/* backgammon? */
|
|
mflag = 0;
|
|
l = bar + 7 * cturn;
|
|
for (i = bar; i != l; i += cturn)
|
|
if (board[i] * cturn)
|
|
mflag++;
|
|
|
|
/* compute game value */
|
|
if (tflag)
|
|
curmove(20, 0);
|
|
if (*offopp == 15 && (*offptr == 0 || *offptr == -15)) {
|
|
if (mflag) {
|
|
writel(bgammon);
|
|
gvalue *= 3;
|
|
} else {
|
|
writel(gammon);
|
|
gvalue *= 2;
|
|
}
|
|
}
|
|
/* report situation */
|
|
if (cturn == -1) {
|
|
writel("Red wins ");
|
|
rscore += gvalue;
|
|
} else {
|
|
writel("White wins ");
|
|
wscore += gvalue;
|
|
}
|
|
wrint(gvalue);
|
|
writel(" point");
|
|
if (gvalue > 1)
|
|
writec('s');
|
|
writel(".\n");
|
|
|
|
/* write score */
|
|
wrscore();
|
|
|
|
/* see if he wants another game */
|
|
writel(again);
|
|
if ((i = yorn('S')) == 0)
|
|
break;
|
|
|
|
init();
|
|
if (i == 2) {
|
|
writel(" Save.\n");
|
|
cturn = 0;
|
|
save(0);
|
|
}
|
|
/* yes, reset game */
|
|
wrboard();
|
|
}
|
|
|
|
/* give him a chance to save if game was recovered */
|
|
if (rfl && cturn) {
|
|
writel(svpromt);
|
|
if (yorn(0)) {
|
|
/* re-initialize for recovery */
|
|
init();
|
|
cturn = 0;
|
|
save(0);
|
|
}
|
|
}
|
|
/* leave peacefully */
|
|
getout(0);
|
|
/* NOTREACHED */
|
|
return (0);
|
|
}
|