add ability to toggle the instructions
[unix-history] / usr / src / games / canfield / canfield / canfield.c
/* Copyright (c) 1982 Regents of the University of California */
static char sccsid[] = "@(#)canfield.c 4.2 %G%";
/*
* The canfield program
*
* Authors:
* Originally written: Steve Levine
* Converted to use curses and debugged: Steve Feldman
* Card counting: Kirk McKusick and Mikey Olson
* User interface cleanups: Eric Allman and Kirk McKusick
*/
#include <curses.h>
#include <ctype.h>
#include <signal.h>
#define decksize 52
#define originrow 0
#define origincol 0
#define basecol 1
#define boxcol 42
#define tboxrow 2
#define bboxrow 17
#define movecol 43
#define moverow 16
#define msgcol 43
#define msgrow 15
#define titlecol 30
#define titlerow 0
#define sidecol 1
#define ottlrow 6
#define foundcol 11
#define foundrow 3
#define stockcol 2
#define stockrow 8
#define fttlcol 10
#define fttlrow 1
#define taloncol 2
#define talonrow 13
#define tabrow 8
#define ctoprow 21
#define cbotrow 23
#define cinitcol 14
#define cheightcol 1
#define cwidthcol 4
#define handstatrow 21
#define handstatcol 7
#define talonstatrow 22
#define talonstatcol 7
#define stockstatrow 23
#define stockstatcol 7
#define Ace 1
#define Jack 11
#define Queen 12
#define King 13
#define atabcol 11
#define btabcol 18
#define ctabcol 25
#define dtabcol 32
#define spades 's'
#define clubs 'c'
#define hearts 'h'
#define diamonds 'd'
#define black 'b'
#define red 'r'
#define stk 1
#define tal 2
#define tab 3
#define INCRHAND(row, col) {\
row -= cheightcol;\
if (row < ctoprow) {\
row = cbotrow;\
col += cwidthcol;\
}\
}
#define DECRHAND(row, col) {\
row += cheightcol;\
if (row > cbotrow) {\
row = ctoprow;\
col -= cwidthcol;\
}\
}
struct cardtype {
char suit;
char color;
bool visible;
int rank;
struct cardtype *next;
};
#define NIL ((struct cardtype *) -1)
struct cardtype *deck[decksize];
struct cardtype cards[decksize];
struct cardtype *bottom[4], *found[4], *tableau[4];
struct cardtype *talon, *hand, *stock, *basecard;
int length[4];
int cardsoff, base, cinhand, taloncnt, stockcnt, timesthru;
char suitmap[4] = {spades, clubs, hearts, diamonds};
char colormap[4] = {black, black, red, red};
char pilemap[4] = {atabcol, btabcol, ctabcol, dtabcol};
char srcpile, destpile;
int mtforigin, tempbase;
int coldcol, cnewcol, coldrow, cnewrow;
bool errmsg, done;
bool mtfdone, Cflag = FALSE, Iflag = TRUE;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* The following procedures print the board onto the screen using the
* addressible cursor. The end of these procedures will also be
* separated from the rest of the program.
*/
/* procedure to set the move command box */
movebox()
{
printtopinstructions();
move(moverow, boxcol);
printw("| |");
move(msgrow, boxcol);
printw("| |");
printbottominstructions();
refresh();
}
/*
* print directions above move box
*/
printtopinstructions()
{
move(tboxrow, boxcol);
printw("*--------------------------*");
move(tboxrow + 1, boxcol);
printw("| MOVES |");
move(tboxrow + 2, boxcol);
printw("|s# = stock to tableau |");
move(tboxrow + 3, boxcol);
printw("|sf = stock to foundation |");
move(tboxrow + 4, boxcol);
printw("|t# = talon to tableau |");
move(tboxrow + 5, boxcol);
printw("|tf = talon to foundation |");
move(tboxrow + 6, boxcol);
printw("|## = tableau to tableau |");
move(tboxrow + 7, boxcol);
printw("|#f = tableau to foundation|");
move(tboxrow + 8, boxcol);
printw("|ht = hand to talon |");
move(tboxrow + 9, boxcol);
printw("|c = toggle card counting |");
move(tboxrow + 10, boxcol);
printw("|i = toggle instructions |");
move(tboxrow + 11, boxcol);
printw("|q = quit to end the game |");
move(tboxrow + 12, boxcol);
printw("|==========================|");
}
/*
* clear directions above move box
*/
cleartopinstructions()
{
int i;
for (i = 0; i <= 11; i++) {
move(tboxrow + i, boxcol);
printw(" ");
}
move(tboxrow + 12, boxcol);
printw("*--------------------------*");
}
/*
* print instructions below move box
*/
printbottominstructions()
{
move(bboxrow, boxcol);
printw("|Replace # with the number |");
move(bboxrow + 1, boxcol);
printw("|of the tableau you want. |");
move(bboxrow + 2, boxcol);
printw("*--------------------------*");
}
/*
* clear directions below move box
*/
clearbottominstructions()
{
int i;
move(bboxrow, boxcol);
printw("*--------------------------*");
for (i = 1; i <= 2; i++) {
move(bboxrow + i, boxcol);
printw(" ");
}
}
/*
* procedure to put the board on the screen using addressable cursor
*/
makeboard()
{
clear();
refresh();
move(titlerow, titlecol);
printw("=-> CANFIELD <-=");
move(fttlrow, fttlcol);
printw("foundation");
move(foundrow - 1, fttlcol);
printw("=---= =---= =---= =---=");
move(foundrow, fttlcol);
printw("| | | | | | | |");
move(foundrow + 1, fttlcol);
printw("=---= =---= =---= =---=");
move(ottlrow, sidecol);
printw("stock tableau");
move(stockrow - 1, sidecol);
printw("=---=");
move(stockrow, sidecol);
printw("| |");
move(stockrow + 1, sidecol);
printw("=---=");
move(talonrow - 2, sidecol);
printw("talon");
move(talonrow - 1, sidecol);
printw("=---=");
move(talonrow, sidecol);
printw("| |");
move(talonrow + 1, sidecol);
printw("=---=");
move(tabrow - 1, atabcol);
printw("-1- -2- -3- -4-");
movebox();
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* clean up the board for another game */
cleanupboard()
{
int cnt, row, col;
struct cardtype *ptr;
if (Cflag) {
clearstat();
for(ptr = stock, row = stockrow;
ptr != NIL;
ptr = ptr->next, row++) {
move(row, sidecol);
printw(" ");
}
move(row, sidecol);
printw(" ");
move(stockrow + 1, sidecol);
printw("=---=");
move(talonrow - 2, sidecol);
printw("talon");
move(talonrow - 1, sidecol);
printw("=---=");
move(talonrow + 1, sidecol);
printw("=---=");
}
move(stockrow, sidecol);
printw("| |");
move(talonrow, sidecol);
printw("| |");
move(foundrow, fttlcol);
printw("| | | | | | | |");
for (cnt = 0; cnt < 4; cnt++) {
switch(cnt) {
case 0:
col = atabcol;
break;
case 1:
col = btabcol;
break;
case 2:
col = ctabcol;
break;
case 3:
col = dtabcol;
break;
}
for(ptr = tableau[cnt], row = tabrow;
ptr != NIL;
ptr = ptr->next, row++)
removecard(col, row);
}
}
/* procedure to create a deck of cards */
initdeck(deck)
struct cardtype *deck[];
{
int i;
int scnt;
char s;
int r;
i = 0;
for (scnt=0; scnt<4; scnt++) {
s = suitmap[scnt];
for (r=Ace; r<=King; r++) {
deck[i] = &cards[i];
cards[i].rank = r;
cards[i].suit = s;
cards[i].color = colormap[scnt];
cards[i].next = NIL;
i++;
}
}
}
/* procedure to shuffle the deck */
shuffle(deck)
struct cardtype *deck[];
{
int i,j;
struct cardtype *temp;
for (i=0; i<decksize; i++)
deck[i]->visible = FALSE;
for (i = decksize-1; i>=0; i--) {
j = rand() % decksize;
if (i != j) {
temp = deck[i];
deck[i] = deck[j];
deck[j] = temp;
}
}
}
/* procedure to remove the card from the board */
removecard(a, b)
{
move(b, a);
printw(" ");
}
/* procedure to print the cards on the board */
printrank(a, b, cp)
struct cardtype *cp;
{
move(b, a);
switch (cp->rank) {
case 2: case 3: case 4: case 5: case 6: case 7:
case 8: case 9: case 10:
printw("%2d", cp->rank);
break;
case Ace:
printw(" A");
break;
case Jack:
printw(" J");
break;
case Queen:
printw(" Q");
break;
case King:
printw(" K");
}
}
printcard(a, b, cp)
int a,b;
struct cardtype *cp;
{
if (cp == NIL)
removecard(a, b);
else if (cp->visible == FALSE) {
move(b, a);
printw(" ? ");
} else {
printrank(a, b, cp);
addch(cp->suit);
}
}
/*
* procedure to move the top card from one location to the top
* of another location. The pointers always point to the top
* of the piles.
*/
transit(source, dest)
struct cardtype **source, **dest;
{
struct cardtype *temp;
temp = *source;
*source = (*source)->next;
temp->next = *dest;
*dest = temp;
}
/*
* Procedure to set the cards on the foundation base when available.
* Note that it is only called on a foundation pile at the beginning of
* the game, so the pile will have exactly one card in it.
*/
fndbase(cp, column, row)
struct cardtype **cp;
{
bool nomore;
if (*cp != NIL)
do {
if ((*cp)->rank == basecard->rank) {
base++;
printcard(pilemap[base], foundrow, *cp);
if (*cp == tableau[0])
length[0] = length[0] - 1;
if (*cp == tableau[1])
length[1] = length[1] - 1;
if (*cp == tableau[2])
length[2] = length[2] - 1;
if (*cp == tableau[3])
length[3] = length[3] - 1;
transit(cp, &found[base]);
if (cp == &talon)
usedtalon();
if (cp == &stock)
usedstock();
if (*cp != NIL) {
printcard(column, row, *cp);
nomore = FALSE;
} else {
removecard(column, row);
nomore = TRUE;
}
cardsoff++;
} else
nomore = TRUE;
} while (nomore == FALSE);
}
/* procedure to initialize the things necessary for the game */
initgame()
{
register i;
for (i=0; i<18; i++)
deck[i]->visible = TRUE;
stockcnt = 13;
stock = deck[12];
for (i=12; i>=1; i--)
deck[i]->next = deck[i - 1];
deck[0]->next = NIL;
found[0] = deck[13];
deck[13]->next = NIL;
for (i=1; i<4; i++)
found[i] = NIL;
basecard = found[0];
for (i=14; i<18; i++) {
tableau[i - 14] = deck[i];
deck[i]->next = NIL;
}
for (i=0; i<4; i++) {
bottom[i] = tableau[i];
length[i] = tabrow;
}
hand = deck[18];
for (i=18; i<decksize-1; i++)
deck[i]->next = deck[i + 1];
deck[decksize-1]->next = NIL;
talon = NIL;
base = 0;
cinhand = 34;
taloncnt = 0;
timesthru = 0;
cardsoff = 1;
coldrow = ctoprow;
coldcol = cinitcol;
cnewrow = ctoprow;
cnewcol = cinitcol + cwidthcol;
}
/* procedure to print the beginning cards and to start each game */
startgame()
{
register int j;
shuffle(deck);
initgame();
printcard(foundcol, foundrow, found[0]);
printcard(stockcol, stockrow, stock);
printcard(atabcol, tabrow, tableau[0]);
printcard(btabcol, tabrow, tableau[1]);
printcard(ctabcol, tabrow, tableau[2]);
printcard(dtabcol, tabrow, tableau[3]);
printcard(taloncol, talonrow, talon);
move(foundrow - 2, basecol);
printw("Base");
move(foundrow - 1, basecol);
printw("Rank");
printrank(basecol, foundrow, found[0]);
for (j=0; j<=3; j++)
fndbase(&tableau[j], pilemap[j], tabrow);
fndbase(&stock, stockcol, stockrow);
showstat(); /* show card counting info to cheaters */
}
/* procedure to clear the message printed from an error */
clearmsg()
{
int i;
if (errmsg == TRUE) {
errmsg = FALSE;
move(msgrow, msgcol);
for (i=0; i<25; i++)
addch(' ');
refresh();
}
}
/* procedure to print an error message if the move is not listed */
dumberror()
{
errmsg = TRUE;
move(msgrow, msgcol);
printw("Not a proper move ");
}
/* procedure to print an error message if the move is not possible */
destinerror()
{
errmsg = TRUE;
move(msgrow, msgcol);
printw("Error: Can't move there");
}
/* function to see if the source has cards in it */
bool
notempty(cp)
struct cardtype *cp;
{
if (cp == NIL) {
errmsg = TRUE;
move(msgrow, msgcol);
printw("Error: no cards to move");
return (FALSE);
} else
return (TRUE);
}
/* function to see if the rank of one card is less than another */
bool
ranklower(cp1, cp2)
struct cardtype *cp1, *cp2;
{
if (cp2->rank == Ace)
if (cp1->rank == King)
return (TRUE);
else
return (FALSE);
else if (cp1->rank + 1 == cp2->rank)
return (TRUE);
else
return (FALSE);
}
/* function to check the cardcolor for moving to a tableau */
bool
diffcolor(cp1, cp2)
struct cardtype *cp1, *cp2;
{
if (cp1->color == cp2->color)
return (FALSE);
else
return (TRUE);
}
/* function to see if the card can move to the tableau */
bool
tabok(cp, des)
struct cardtype *cp;
{
if ((cp == stock) && (tableau[des] == NIL))
return (TRUE);
else if (tableau[des] == NIL)
if (stock == NIL)
return (TRUE);
else
return (FALSE);
else if (ranklower(cp, tableau[des]) && diffcolor(cp, tableau[des]))
return (TRUE);
else
return (FALSE);
}
/* procedure to turn the cards onto the talon from the deck */
movetotalon()
{
int i, fin;
if (cinhand >= 3)
fin = 3;
else if (cinhand > 0)
fin = cinhand;
else if (talon != NIL) {
timesthru++;
errmsg = TRUE;
move(msgrow, msgcol);
if (timesthru != 4) {
printw("Talon is now the new hand");
while (talon != NIL) {
transit(&talon, &hand);
cinhand++;
}
if (cinhand >= 3)
fin = 3;
else
fin = cinhand;
taloncnt = 0;
coldrow = ctoprow;
coldcol = cinitcol;
cnewrow = ctoprow;
cnewcol = cinitcol + cwidthcol;
clearstat();
showstat();
} else {
fin = 0;
done = TRUE;
printw("I believe you have lost");
refresh();
sleep(5);
}
} else {
errmsg = TRUE;
move(msgrow, msgcol);
printw("Talon and hand are empty");
fin = 0;
}
for (i=0; i<fin; i++) {
transit(&hand, &talon);
INCRHAND(cnewrow, cnewcol);
INCRHAND(coldrow, coldcol);
removecard(cnewcol, cnewrow);
if (i == fin - 1)
talon->visible = TRUE;
if (Cflag)
printcard(coldcol, coldrow, talon);
}
if (fin != 0) {
printcard(taloncol, talonrow, talon);
cinhand -= fin;
taloncnt += fin;
if (Cflag) {
move(handstatrow, handstatcol);
printw("%3d", cinhand);
move(talonstatrow, talonstatcol);
printw("%3d", taloncnt);
}
fndbase(&talon, taloncol, talonrow);
}
}
/* procedure to print card counting info on screen */
showstat()
{
int row, col;
register struct cardtype *ptr;
if (Cflag) {
move(talonstatrow, talonstatcol - 7);
printw("Talon: %3d", taloncnt);
move(handstatrow, handstatcol - 7);
printw("Hand: %3d", cinhand);
move(stockstatrow, stockstatcol - 7);
printw("Stock: %3d", stockcnt);
for ( row = coldrow, col = coldcol, ptr = talon;
ptr != NIL;
ptr = ptr->next ) {
printcard(col, row, ptr);
DECRHAND(row, col);
}
for ( row = cnewrow, col = cnewcol, ptr = hand;
ptr != NIL;
ptr = ptr->next ) {
INCRHAND(row, col);
printcard(col, row, ptr);
}
}
}
/* procedure to clear card counting info from screen */
clearstat()
{
int row;
move(talonstatrow, talonstatcol - 7);
printw(" ");
move(handstatrow, handstatcol - 7);
printw(" ");
move(stockstatrow, stockstatcol - 7);
printw(" ");
for ( row = ctoprow ; row <= cbotrow ; row++ ) {
move(row, cinitcol);
printw("%56s", " ");
}
}
/* procedure to update card counting base */
usedtalon()
{
removecard(coldcol, coldrow);
DECRHAND(coldrow, coldcol);
if (talon != NIL && (talon->visible == FALSE)) {
talon->visible = TRUE;
if (Cflag)
printcard(coldcol, coldrow, talon);
}
taloncnt--;
if (Cflag) {
move(talonstatrow, talonstatcol);
printw("%3d", taloncnt);
}
}
/* procedure to update stock card counting base */
usedstock()
{
stockcnt--;
if (Cflag) {
move(stockstatrow, stockstatcol);
printw("%3d", stockcnt);
}
}
/* let 'em know how they lost! */
showcards()
{
register struct cardtype *ptr;
int row;
if (!Cflag)
return;
for (ptr = talon; ptr != NIL; ptr = ptr->next)
ptr->visible = TRUE;
for (ptr = hand; ptr != NIL; ptr = ptr->next)
ptr->visible = TRUE;
showstat();
move(stockrow + 1, sidecol);
printw(" ");
move(talonrow - 2, sidecol);
printw(" ");
move(talonrow - 1, sidecol);
printw(" ");
move(talonrow, sidecol);
printw(" ");
move(talonrow + 1, sidecol);
printw(" ");
for (ptr = stock, row = stockrow; ptr != NIL; ptr = ptr->next, row++) {
move(row, stockcol - 1);
printw("| |");
printcard(stockcol, row, ptr);
}
if (stock == NIL) {
move(row, stockcol - 1);
printw("| |");
row++;
}
move(handstatrow, handstatcol - 7);
printw(" ");
move(row, stockcol - 1);
printw("=---=");
getcmd(moverow, movecol, "Hit return to exit");
}
/* procedure to move a card from the stock or talon to the tableau */
simpletableau(cp, des)
struct cardtype **cp;
{
int origin;
if (notempty(*cp)) {
if (tabok(*cp, des)) {
if (*cp == stock)
origin = stk;
else
origin = tal;
if (tableau[des] == NIL)
bottom[des] = *cp;
transit(cp, &tableau[des]);
length[des]++;
printcard(pilemap[des], length[des], tableau[des]);
timesthru = 0;
if (origin == stk) {
usedstock();
printcard(stockcol, stockrow, stock);
} else {
usedtalon();
printcard(taloncol, talonrow, talon);
}
} else
destinerror();
}
}
tabprint(sour, des)
{
int dlength, slength, i;
struct cardtype *tempcard;
for (i=tabrow; i<=length[sour]; i++)
removecard(pilemap[sour], i);
dlength = length[des] + 1;
slength = length[sour];
if (slength == tabrow)
printcard(pilemap[des], dlength, tableau[sour]);
else
while (slength != tabrow - 1) {
tempcard = tableau[sour];
for (i=1; i<=slength-tabrow; i++)
tempcard = tempcard->next;
printcard(pilemap[des], dlength, tempcard);
slength--;
dlength++;
}
}
/* procedure to move from the tableau to the tableau */
tabtotab(sour, des)
{
struct cardtype *temp;
if (notempty(tableau[sour])) {
if (tabok(bottom[sour], des)) {
tabprint(sour, des);
temp = bottom[sour];
bottom[sour] = NIL;
temp->next = tableau[des];
tableau[des] = tableau[sour];
tableau[sour] = NIL;
length[des] = length[des] + (length[sour] - (tabrow - 1));
length[sour] = tabrow - 1;
timesthru = 0;
} else
destinerror();
}
}
/* functions to see if the card can go onto the foundation */
bool
rankhigher(cp, let)
struct cardtype *cp;
{
if (found[let]->rank == King)
if (cp->rank == Ace)
return(TRUE);
else
return(FALSE);
else if (cp->rank - 1 == found[let]->rank)
return(TRUE);
else
return(FALSE);
}
samesuit(cp, let)
struct cardtype *cp;
{
if (cp->suit == found[let]->suit)
return (TRUE);
else
return (FALSE);
}
/* procedure to move a card to the correct foundation pile */
movetofound(cp, source)
struct cardtype **cp;
{
tempbase = 0;
mtfdone = FALSE;
if (notempty(*cp)) {
do {
if (found[tempbase] != NIL)
if (rankhigher(*cp, tempbase)
&& samesuit(*cp, tempbase)) {
if (*cp == stock)
mtforigin = stk;
else if (*cp == talon)
mtforigin = tal;
else
mtforigin = tab;
transit(cp, &found[tempbase]);
printcard(pilemap[tempbase],
foundrow, found[tempbase]);
timesthru = 0;
if (mtforigin == stk) {
usedstock();
printcard(stockcol, stockrow, stock);
} else if (mtforigin == tal) {
usedtalon();
printcard(taloncol, talonrow, talon);
} else {
removecard(pilemap[source], length[source]);
length[source]--;
}
cardsoff++;
mtfdone = TRUE;
} else
tempbase++;
else
tempbase++;
} while ((tempbase != 4) && !mtfdone);
if (!mtfdone)
destinerror();
}
}
/* procedure to get a command */
getcmd(row, col, cp)
int row, col;
char *cp;
{
char cmd[2], ch;
int i;
i = 0;
move(row, col);
printw("%-24s", cp);
col += 1 + strlen(cp);
move(row, col);
refresh();
do {
ch = getch() & 0177;
if (ch >= 'A' && ch <= 'Z')
ch += ('a' - 'A');
if (ch == '\f') {
wrefresh(curscr);
refresh();
} else if (i >= 2 && ch != _tty.sg_erase && ch != _tty.sg_kill) {
if (ch != '\n' && ch != '\r' && ch != ' ')
write(1, "\007", 1);
} else if (ch == _tty.sg_erase && i > 0) {
printw("\b \b");
refresh();
i--;
} else if (ch == _tty.sg_kill && i > 0) {
while (i > 0) {
printw("\b \b");
i--;
}
refresh();
} else if (ch == '\032') { /* Control-Z */
suspend();
move(row, col + i);
refresh();
} else if (isprint(ch)) {
cmd[i++] = ch;
addch(ch);
refresh();
}
} while (ch != '\n' && ch != '\r' && ch != ' ');
srcpile = cmd[0];
destpile = cmd[1];
}
/* Suspend the game (shell escape if no process control on system) */
suspend()
{
#ifndef SIGTSTP
char *sh;
#endif
move(21, 0);
refresh();
endwin();
fflush(stdout);
#ifdef SIGTSTP
kill(getpid(), SIGTSTP);
#else
sh = getenv("SHELL");
if (sh == NULL)
sh = "/bin/sh";
system(sh);
#endif
raw();
noecho();
}
/* procedure to evaluate and make the specific moves */
movecard()
{
int source, dest;
done = FALSE;
errmsg = FALSE;
do {
if (cardsoff == 52) {
refresh();
srcpile = 'q';
} else
getcmd(moverow, movecol, "Move:");
clearmsg();
if (srcpile >= '1' && srcpile <= '4')
source = (int) (srcpile - '1');
if (destpile >= '1' && destpile <= '4')
dest = (int) (destpile - '1');
switch (srcpile) {
case 't':
if (destpile == 'f' || destpile == 'F')
movetofound(&talon, source);
else if (destpile >= '1' && destpile <= '4')
simpletableau(&talon, dest);
else
dumberror();
break;
case 's':
if (destpile == 'f' || destpile == 'F')
movetofound(&stock, source);
else if (destpile >= '1' && destpile <= '4')
simpletableau(&stock, dest);
else dumberror();
break;
case 'h':
if (destpile == 't' || destpile == 'T')
movetotalon();
else dumberror();
break;
case 'q':
showcards();
done = TRUE;
break;
case 'i':
Iflag = !Iflag;
if (Iflag) {
printtopinstructions();
printbottominstructions();
} else {
cleartopinstructions();
clearbottominstructions();
}
break;
case 'c':
Cflag = !Cflag;
if (Cflag)
showstat();
else
clearstat();
break;
case '1': case '2': case '3': case '4':
if (destpile == 'f' || destpile == 'F')
movetofound(&tableau[source], source);
else if (destpile >= '1' && destpile <= '4')
tabtotab(source, dest);
else dumberror();
break;
default:
dumberror();
}
fndbase(&stock, stockcol, stockrow);
fndbase(&talon, taloncol, talonrow);
} while (!done);
}
/* procedure to printout instructions */
instruct()
{
move(originrow, origincol);
printw("This is the game of solitaire called Canfield. Do\n");
printw("you want instructions for the game?");
do {
getcmd(originrow + 3, origincol, "y or n?");
} while (srcpile != 'y' && srcpile != 'n');
if (srcpile == 'y') {
clear();
refresh();
printw("Here are brief instuctions to the game of Canfield:\n");
printw("\n");
printw(" If you have never played solitaire before, it is recom-\n");
printw("mended that you consult a solitaire instruction book. In\n");
printw("Canfield, tableau cards may be built on each other downward\n");
printw("in alternate colors. An entire pile must be moved as a unit\n");
printw("in building. Top cards of the piles are available to be able\n");
printw("to be played on foundations, but never into empty spaces.\n");
printw("\n");
printw(" Spaces must be filled from the stock. The top card of\n");
printw("the stock also is available to be played on foundations or\n");
printw("built on tableau piles. After the stock is exhausted, ta-\n");
printw("bleau spaces may be filled from the talon and the player may\n");
printw("keep them open until he wishes to use them.\n");
printw("\n");
printw(" Cards are dealt from the hand to the talon by threes\n");
printw("and this repeats until there are no more cards in the hand\n");
printw("or the player quits. To have cards dealt onto the talon the\n");
printw("player types 'ht' for his move. Foundation base cards are\n");
printw("also automatically moved to the foundation when they become\n");
printw("available.\n\n");
printw("push any key when you are finished: ");
refresh();
getch();
}
}
/* procedure to initialize the game */
initall()
{
srand(getpid());
initdeck(deck);
}
/* procedure to end the game */
bool
finish()
{
int row, col;
if (cardsoff == 52) {
clear();
refresh();
move(originrow, origincol);
printw("CONGRATULATIONS!\n");
printw("You won the game. That is a feat to be proud of.\n");
move(originrow + 4, origincol);
printw("Wish to play again? ");
row = originrow + 5;
col = origincol;
} else {
move(msgrow, msgcol);
printw("You got %d card", cardsoff);
if (cardsoff > 1)
printw("s");
printw(" off ");
getcmd(moverow, movecol, "Hit return to continue");
move(msgrow, msgcol);
printw("Wish to play again? ");
row = moverow;
col = movecol;
}
do {
getcmd(row, col, "y or n?");
} while (srcpile != 'y' && srcpile != 'n');
errmsg = TRUE;
clearmsg();
if (srcpile == 'y')
return (FALSE);
else
return (TRUE);
}
main(argc, argv)
int argc;
char *argv[];
{
#ifdef MAXLOAD
double vec[3];
loadav(vec);
if (vec[2] >= MAXLOAD) {
puts("The system load is too high. Try again later.");
exit(0);
}
#endif
initscr();
raw();
noecho();
initall();
instruct();
makeboard();
for (;;) {
startgame();
movecard();
if (finish())
break;
if (cardsoff == 52)
makeboard();
else
cleanupboard();
}
clear();
move(22,0);
refresh();
endwin();
}