date and time created 82/10/24 18:25:54 by mckusick
authorKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Mon, 25 Oct 1982 10:25:54 +0000 (02:25 -0800)
committerKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Mon, 25 Oct 1982 10:25:54 +0000 (02:25 -0800)
SCCS-vsn: games/canfield/canfield/canfield.c 4.1

usr/src/games/canfield/canfield/canfield.c [new file with mode: 0644]

diff --git a/usr/src/games/canfield/canfield/canfield.c b/usr/src/games/canfield/canfield/canfield.c
new file mode 100644 (file)
index 0000000..10f684d
--- /dev/null
@@ -0,0 +1,1145 @@
+/* Copyright (c) 1982 Regents of the University of California */
+
+static char sccsid[] = "@(#)canfield.c 4.1 %G%";
+
+/*
+ * The canfield program
+ *
+ * Authors:
+ *     Originally written: Steve Levine
+ *     Converted to use curses and debugged: Steve Feldman
+ *     Card counting: Kirk McKusick and Mikey Olson
+ */
+
+#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         16
+#define        movecol         43
+#define        moverow         15
+#define        msgcol          43
+#define        msgrow          14
+#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;
+
+
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * 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()
+{
+           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("|q = quit to end the game  |");
+           move(tboxrow + 11, boxcol);
+           printw("|==========================|");
+           move(moverow, boxcol);
+           printw("|                          |");
+           move(msgrow, boxcol);
+           printw("|                          |");
+           move(bboxrow, boxcol);
+           printw("|Replace the # with the    |");
+           move(bboxrow + 1, boxcol);
+           printw("|number of the tableau you |");
+           move(bboxrow + 2, boxcol);
+           printw("|want, 1, 2, 3, or 4.      |");
+           move(bboxrow + 3, boxcol);
+           printw("*--------------------------*");
+           refresh();
+}
+
+/* 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 '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();
+}