2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * @(#) Copyright (c) 1980, 1993 The Regents of the University of California. All rights reserved.
34 * @(#)canfield.c 8.1 (Berkeley) 5/31/93
35 * $FreeBSD: src/games/canfield/canfield/canfield.c,v 1.11 1999/12/12 07:25:13 billf Exp $
36 * $DragonFly: src/games/canfield/canfield/canfield.c,v 1.3 2003/11/12 14:53:52 eirikn Exp $
40 * The canfield program
43 * Originally written: Steve Levine
44 * Converted to use curses and debugged: Steve Feldman
45 * Card counting: Kirk McKusick and Mikey Olson
46 * User interface cleanups: Eric Allman and Kirk McKusick
47 * Betting by Kirk McKusick
50 #include <sys/types.h>
61 #include "pathnames.h"
92 #define handstatrow 21
94 #define talonstatrow 22
95 #define talonstatcol 7
96 #define stockstatrow 23
97 #define stockstatcol 7
117 #define INCRHAND(row, col) {\
119 if (row < ctoprow) {\
124 #define DECRHAND(row, col) {\
126 if (row > cbotrow) {\
139 struct cardtype *next;
142 #define NIL ((struct cardtype *) -1)
144 struct cardtype *deck[decksize];
145 struct cardtype cards[decksize];
146 struct cardtype *bottom[4], *found[4], *tableau[4];
147 struct cardtype *talon, *hand, *stock, *basecard;
149 int cardsoff, base, cinhand, taloncnt, stockcnt, timesthru;
150 char suitmap[4] = {spades, clubs, hearts, diamonds};
151 char colormap[4] = {black, black, red, red};
152 char pilemap[4] = {atabcol, btabcol, ctabcol, dtabcol};
153 char srcpile, destpile;
154 int mtforigin, tempbase;
155 int coldcol, cnewcol, coldrow, cnewrow;
157 bool mtfdone, Cflag = FALSE;
158 #define INSTRUCTIONBOX 1
161 int status = INSTRUCTIONBOX;
165 * Basic betting costs
167 #define costofhand 13
168 #define costofinspection 13
169 #define costofgame 26
170 #define costofrunthroughhand 5
171 #define costofinformation 1
172 #define secondsperdollar 60
173 #define maxtimecharge 3
174 #define valuepercardup 5
176 * Variables associated with betting
179 long hand; /* cost of dealing hand */
180 long inspection; /* cost of inspecting hand */
181 long game; /* cost of buying game */
182 long runs; /* cost of running through hands */
183 long information; /* cost of information */
184 long thinktime; /* cost of thinking time */
185 long wins; /* total winnings */
186 long worth; /* net worth after costs */
188 struct betinfo this, game, total;
189 bool startedgame = FALSE, infullgame = FALSE;
195 void cleanupboard (void);
196 void clearabovemovebox (void);
197 void clearbelowmovebox (void);
198 void clearmsg (void);
199 void clearstat (void);
200 void destinerror (void);
201 bool diffcolor (struct cardtype *, struct cardtype *);
202 void dumberror (void);
204 void fndbase (struct cardtype **, int, int);
205 void getcmd (int, int, char *);
207 void initdeck (struct cardtype *[]);
208 void initgame (void);
209 void instruct (void);
210 void makeboard (void);
212 void movecard (void);
213 void movetofound (struct cardtype **, int);
214 void movetotalon (void);
215 bool notempty (struct cardtype *);
216 void printbottombettingbox (void);
217 void printbottominstructions (void);
218 void printcard (int, int, struct cardtype *);
219 void printrank (int, int, struct cardtype *, bool);
220 void printtopbettingbox (void);
221 void printtopinstructions (void);
222 bool rankhigher (struct cardtype *, int);
223 bool ranklower (struct cardtype *, struct cardtype *);
224 void removecard (int, int);
225 bool samesuit (struct cardtype *, int);
226 void showcards (void);
227 void showstat (void);
228 void shuffle (struct cardtype *[]);
229 void simpletableau (struct cardtype **, int);
230 void startgame (void);
232 bool tabok (struct cardtype *, int);
233 void tabprint (int, int);
234 void tabtotab (int, int);
235 void transit (struct cardtype **, struct cardtype **);
236 void updatebettinginfo (void);
237 void usedstock (void);
238 void usedtalon (void);
241 * The following procedures print the board onto the screen using the
242 * addressible cursor. The end of these procedures will also be
243 * separated from the rest of the program.
245 * procedure to set the move command box
252 printtopbettingbox();
258 printtopinstructions();
261 move(moverow, boxcol);
263 move(msgrow, boxcol);
267 printbottombettingbox();
273 printbottominstructions();
280 * print directions above move box
283 printtopinstructions()
285 move(tboxrow, boxcol);
286 printw("*----------------------------------*");
287 move(tboxrow + 1, boxcol);
289 move(tboxrow + 2, boxcol);
290 printw("|s# = stock to tableau |");
291 move(tboxrow + 3, boxcol);
292 printw("|sf = stock to foundation |");
293 move(tboxrow + 4, boxcol);
294 printw("|t# = talon to tableau |");
295 move(tboxrow + 5, boxcol);
296 printw("|tf = talon to foundation |");
297 move(tboxrow + 6, boxcol);
298 printw("|## = tableau to tableau |");
299 move(tboxrow + 7, boxcol);
300 printw("|#f = tableau to foundation |");
301 move(tboxrow + 8, boxcol);
302 printw("|ht = hand to talon |");
303 move(tboxrow + 9, boxcol);
304 printw("|c = toggle card counting |");
305 move(tboxrow + 10, boxcol);
306 printw("|b = present betting information |");
307 move(tboxrow + 11, boxcol);
308 printw("|q = quit to end the game |");
309 move(tboxrow + 12, boxcol);
310 printw("|==================================|");
314 * Print the betting box.
320 move(tboxrow, boxcol);
321 printw("*----------------------------------*");
322 move(tboxrow + 1, boxcol);
323 printw("|Costs Hand Game Total |");
324 move(tboxrow + 2, boxcol);
326 move(tboxrow + 3, boxcol);
327 printw("| Inspections |");
328 move(tboxrow + 4, boxcol);
330 move(tboxrow + 5, boxcol);
332 move(tboxrow + 6, boxcol);
333 printw("| Information |");
334 move(tboxrow + 7, boxcol);
335 printw("| Think time |");
336 move(tboxrow + 8, boxcol);
337 printw("|Total Costs |");
338 move(tboxrow + 9, boxcol);
339 printw("|Winnings |");
340 move(tboxrow + 10, boxcol);
341 printw("|Net Worth |");
342 move(tboxrow + 11, boxcol);
344 move(tboxrow + 12, boxcol);
345 printw("|==================================|");
349 * clear info above move box
356 for (i = 0; i <= 11; i++) {
357 move(tboxrow + i, boxcol);
360 move(tboxrow + 12, boxcol);
361 printw("*----------------------------------*");
365 * print instructions below move box
368 printbottominstructions()
370 move(bboxrow, boxcol);
371 printw("|Replace # with the number of the |");
372 move(bboxrow + 1, boxcol);
373 printw("|tableau you want. |");
374 move(bboxrow + 2, boxcol);
375 printw("*----------------------------------*");
379 * print betting information below move box
382 printbottombettingbox()
384 move(bboxrow, boxcol);
385 printw("|x = toggle information box |");
386 move(bboxrow + 1, boxcol);
387 printw("|i = list playing instructions |");
388 move(bboxrow + 2, boxcol);
389 printw("*----------------------------------*");
393 * clear info below move box
400 move(bboxrow, boxcol);
401 printw("*----------------------------------*");
402 for (i = 1; i <= 2; i++) {
403 move(bboxrow + i, boxcol);
409 * procedure to put the board on the screen using addressable cursor
416 move(titlerow, titlecol);
417 printw("=-> CANFIELD <-=");
418 move(fttlrow, fttlcol);
419 printw("foundation");
420 move(foundrow - 1, fttlcol);
421 printw("=---= =---= =---= =---=");
422 move(foundrow, fttlcol);
423 printw("| | | | | | | |");
424 move(foundrow + 1, fttlcol);
425 printw("=---= =---= =---= =---=");
426 move(ottlrow, sidecol);
427 printw("stock tableau");
428 move(stockrow - 1, sidecol);
430 move(stockrow, sidecol);
432 move(stockrow + 1, sidecol);
434 move(talonrow - 2, sidecol);
436 move(talonrow - 1, sidecol);
438 move(talonrow, sidecol);
440 move(talonrow + 1, sidecol);
442 move(tabrow - 1, atabcol);
443 printw("-1- -2- -3- -4-");
448 * clean up the board for another game
454 struct cardtype *ptr;
459 for(ptr = stock, row = stockrow;
461 ptr = ptr->next, row++) {
467 move(stockrow + 1, sidecol);
469 move(talonrow - 2, sidecol);
471 move(talonrow - 1, sidecol);
473 move(talonrow + 1, sidecol);
476 move(stockrow, sidecol);
478 move(talonrow, sidecol);
480 move(foundrow, fttlcol);
481 printw("| | | | | | | |");
482 for (cnt = 0; cnt < 4; cnt++) {
497 for(ptr = tableau[cnt], row = tabrow;
499 ptr = ptr->next, row++)
500 removecard(col, row);
505 * procedure to create a deck of cards
509 struct cardtype *deck[];
517 for (scnt=0; scnt<4; scnt++) {
519 for (r=Ace; r<=King; r++) {
523 cards[i].color = colormap[scnt];
531 * procedure to shuffle the deck
535 struct cardtype *deck[];
538 struct cardtype *temp;
540 for (i=0; i<decksize; i++) {
541 deck[i]->visible = FALSE;
542 deck[i]->paid = FALSE;
544 for (i = decksize-1; i>=0; i--) {
545 j = random() % decksize;
555 * procedure to remove the card from the board
565 * procedure to print the cards on the board
568 printrank(a, b, cp, inverse)
578 case 2: case 3: case 4: case 5: case 6: case 7:
579 case 8: case 9: case 10:
580 printw("%d", cp->rank);
599 * procedure to print out a card
608 else if (cp->visible == FALSE) {
612 bool inverse = (cp->suit == 'd' || cp->suit == 'h');
614 printrank(a, b, cp, inverse);
624 * procedure to move the top card from one location to the top
625 * of another location. The pointers always point to the top
629 transit(source, dest)
630 struct cardtype **source, **dest;
632 struct cardtype *temp;
635 *source = (*source)->next;
641 * Procedure to set the cards on the foundation base when available.
642 * Note that it is only called on a foundation pile at the beginning of
643 * the game, so the pile will have exactly one card in it.
646 fndbase(cp, column, row)
647 struct cardtype **cp;
653 if ((*cp)->rank == basecard->rank) {
655 printcard(pilemap[base], foundrow, *cp);
656 if (*cp == tableau[0])
657 length[0] = length[0] - 1;
658 if (*cp == tableau[1])
659 length[1] = length[1] - 1;
660 if (*cp == tableau[2])
661 length[2] = length[2] - 1;
662 if (*cp == tableau[3])
663 length[3] = length[3] - 1;
664 transit(cp, &found[base]);
670 printcard(column, row, *cp);
673 removecard(column, row);
678 this.wins += valuepercardup;
679 game.wins += valuepercardup;
680 total.wins += valuepercardup;
684 } while (nomore == FALSE);
688 * procedure to initialize the things necessary for the game
695 for (i=0; i<18; i++) {
696 deck[i]->visible = TRUE;
697 deck[i]->paid = TRUE;
701 for (i=12; i>=1; i--)
702 deck[i]->next = deck[i - 1];
705 deck[13]->next = NIL;
709 for (i=14; i<18; i++) {
710 tableau[i - 14] = deck[i];
713 for (i=0; i<4; i++) {
714 bottom[i] = tableau[i];
718 for (i=18; i<decksize-1; i++)
719 deck[i]->next = deck[i + 1];
720 deck[decksize-1]->next = NIL;
730 cnewcol = cinitcol + cwidthcol;
734 * procedure to print the beginning cards and to start each game
743 this.hand = costofhand;
744 game.hand += costofhand;
745 total.hand += costofhand;
749 this.information = 0;
754 printcard(foundcol, foundrow, found[0]);
755 printcard(stockcol, stockrow, stock);
756 printcard(atabcol, tabrow, tableau[0]);
757 printcard(btabcol, tabrow, tableau[1]);
758 printcard(ctabcol, tabrow, tableau[2]);
759 printcard(dtabcol, tabrow, tableau[3]);
760 printcard(taloncol, talonrow, talon);
761 move(foundrow - 2, basecol);
763 move(foundrow - 1, basecol);
765 printrank(basecol, foundrow, found[0], 0);
767 fndbase(&tableau[j], pilemap[j], tabrow);
768 fndbase(&stock, stockcol, stockrow);
769 showstat(); /* show card counting info to cheaters */
775 * procedure to clear the message printed from an error
782 if (errmsg == TRUE) {
784 move(msgrow, msgcol);
792 * procedure to print an error message if the move is not listed
798 move(msgrow, msgcol);
799 printw("Not a proper move ");
803 * procedure to print an error message if the move is not possible
809 move(msgrow, msgcol);
810 printw("Error: Can't move there");
814 * function to see if the source has cards in it
822 move(msgrow, msgcol);
823 printw("Error: no cards to move");
830 * function to see if the rank of one card is less than another
834 struct cardtype *cp1, *cp2;
836 if (cp2->rank == Ace)
837 if (cp1->rank == King)
841 else if (cp1->rank + 1 == cp2->rank)
848 * function to check the cardcolor for moving to a tableau
852 struct cardtype *cp1, *cp2;
854 if (cp1->color == cp2->color)
861 * function to see if the card can move to the tableau
867 if ((cp == stock) && (tableau[des] == NIL))
869 else if (tableau[des] == NIL)
871 cp != bottom[0] && cp != bottom[1] &&
872 cp != bottom[2] && cp != bottom[3])
876 else if (ranklower(cp, tableau[des]) && diffcolor(cp, tableau[des]))
883 * procedure to turn the cards onto the talon from the deck
890 if (cinhand <= 3 && cinhand > 0) {
891 move(msgrow, msgcol);
892 printw("Hand is now empty ");
896 else if (cinhand > 0)
898 else if (talon != NIL) {
901 move(msgrow, msgcol);
902 if (timesthru != 4) {
903 printw("Talon is now the new hand");
904 this.runs += costofrunthroughhand;
905 game.runs += costofrunthroughhand;
906 total.runs += costofrunthroughhand;
907 while (talon != NIL) {
908 transit(&talon, &hand);
919 cnewcol = cinitcol + cwidthcol;
925 printw("I believe you have lost");
931 move(msgrow, msgcol);
932 printw("Talon and hand are empty");
935 for (i=0; i<fin; i++) {
936 transit(&hand, &talon);
937 INCRHAND(cnewrow, cnewcol);
938 INCRHAND(coldrow, coldcol);
939 removecard(cnewcol, cnewrow);
941 talon->visible = TRUE;
943 if (talon->paid == FALSE && talon->visible == TRUE) {
944 this.information += costofinformation;
945 game.information += costofinformation;
946 total.information += costofinformation;
949 printcard(coldcol, coldrow, talon);
953 printcard(taloncol, talonrow, talon);
957 move(handstatrow, handstatcol);
958 printw("%3d", cinhand);
959 move(talonstatrow, talonstatcol);
960 printw("%3d", taloncnt);
962 fndbase(&talon, taloncol, talonrow);
968 * procedure to print card counting info on screen
974 struct cardtype *ptr;
978 move(talonstatrow, talonstatcol - 7);
979 printw("Talon: %3d", taloncnt);
980 move(handstatrow, handstatcol - 7);
981 printw("Hand: %3d", cinhand);
982 move(stockstatrow, stockstatcol - 7);
983 printw("Stock: %3d", stockcnt);
984 for ( row = coldrow, col = coldcol, ptr = talon;
987 if (ptr->paid == FALSE && ptr->visible == TRUE) {
989 this.information += costofinformation;
990 game.information += costofinformation;
991 total.information += costofinformation;
993 printcard(col, row, ptr);
996 for ( row = cnewrow, col = cnewcol, ptr = hand;
999 if (ptr->paid == FALSE && ptr->visible == TRUE) {
1001 this.information += costofinformation;
1002 game.information += costofinformation;
1003 total.information += costofinformation;
1006 printcard(col, row, ptr);
1011 * procedure to clear card counting info from screen
1018 move(talonstatrow, talonstatcol - 7);
1020 move(handstatrow, handstatcol - 7);
1022 move(stockstatrow, stockstatcol - 7);
1024 for ( row = ctoprow ; row <= cbotrow ; row++ ) {
1025 move(row, cinitcol);
1026 printw("%56s", " ");
1031 * procedure to update card counting base
1036 removecard(coldcol, coldrow);
1037 DECRHAND(coldrow, coldcol);
1038 if (talon != NIL && (talon->visible == FALSE)) {
1039 talon->visible = TRUE;
1041 this.information += costofinformation;
1042 game.information += costofinformation;
1043 total.information += costofinformation;
1045 printcard(coldcol, coldrow, talon);
1050 move(talonstatrow, talonstatcol);
1051 printw("%3d", taloncnt);
1056 * procedure to update stock card counting base
1063 move(stockstatrow, stockstatcol);
1064 printw("%3d", stockcnt);
1069 * let 'em know how they lost!
1074 struct cardtype *ptr;
1077 if (!Cflag || cardsoff == 52)
1079 for (ptr = talon; ptr != NIL; ptr = ptr->next) {
1080 ptr->visible = TRUE;
1083 for (ptr = hand; ptr != NIL; ptr = ptr->next) {
1084 ptr->visible = TRUE;
1088 move(stockrow + 1, sidecol);
1090 move(talonrow - 2, sidecol);
1092 move(talonrow - 1, sidecol);
1094 move(talonrow, sidecol);
1096 move(talonrow + 1, sidecol);
1098 for (ptr = stock, row = stockrow; ptr != NIL; ptr = ptr->next, row++) {
1099 move(row, stockcol - 1);
1101 printcard(stockcol, row, ptr);
1104 move(row, stockcol - 1);
1108 move(handstatrow, handstatcol - 7);
1110 move(row, stockcol - 1);
1112 if ( cardsoff == 52 )
1113 getcmd(moverow, movecol, "Hit return to exit");
1117 * procedure to update the betting values
1122 long thiscosts, gamecosts, totalcosts;
1123 double thisreturn, gamereturn, totalreturn;
1128 dollars = (now - acctstart) / secondsperdollar;
1130 acctstart += dollars * secondsperdollar;
1131 if (dollars > maxtimecharge)
1132 dollars = maxtimecharge;
1133 this.thinktime += dollars;
1134 game.thinktime += dollars;
1135 total.thinktime += dollars;
1137 thiscosts = this.hand + this.inspection + this.game +
1138 this.runs + this.information + this.thinktime;
1139 gamecosts = game.hand + game.inspection + game.game +
1140 game.runs + game.information + game.thinktime;
1141 totalcosts = total.hand + total.inspection + total.game +
1142 total.runs + total.information + total.thinktime;
1143 this.worth = this.wins - thiscosts;
1144 game.worth = game.wins - gamecosts;
1145 total.worth = total.wins - totalcosts;
1146 thisreturn = ((double)this.wins / (double)thiscosts - 1.0) * 100.0;
1147 gamereturn = ((double)game.wins / (double)gamecosts - 1.0) * 100.0;
1148 totalreturn = ((double)total.wins / (double)totalcosts - 1.0) * 100.0;
1149 if (status != BETTINGBOX)
1151 move(tboxrow + 2, boxcol + 13);
1152 printw("%4d%8d%9d", this.hand, game.hand, total.hand);
1153 move(tboxrow + 3, boxcol + 13);
1154 printw("%4d%8d%9d", this.inspection, game.inspection, total.inspection);
1155 move(tboxrow + 4, boxcol + 13);
1156 printw("%4d%8d%9d", this.game, game.game, total.game);
1157 move(tboxrow + 5, boxcol + 13);
1158 printw("%4d%8d%9d", this.runs, game.runs, total.runs);
1159 move(tboxrow + 6, boxcol + 13);
1160 printw("%4d%8d%9d", this.information, game.information,
1162 move(tboxrow + 7, boxcol + 13);
1163 printw("%4d%8d%9d", this.thinktime, game.thinktime, total.thinktime);
1164 move(tboxrow + 8, boxcol + 13);
1165 printw("%4d%8d%9d", thiscosts, gamecosts, totalcosts);
1166 move(tboxrow + 9, boxcol + 13);
1167 printw("%4d%8d%9d", this.wins, game.wins, total.wins);
1168 move(tboxrow + 10, boxcol + 13);
1169 printw("%4d%8d%9d", this.worth, game.worth, total.worth);
1170 move(tboxrow + 11, boxcol + 13);
1171 printw("%4.0f%%%7.1f%%%8.1f%%", thisreturn, gamereturn, totalreturn);
1175 * procedure to move a card from the stock or talon to the tableau
1178 simpletableau(cp, des)
1179 struct cardtype **cp;
1183 if (notempty(*cp)) {
1184 if (tabok(*cp, des)) {
1189 if (tableau[des] == NIL)
1191 transit(cp, &tableau[des]);
1193 printcard(pilemap[des], length[des], tableau[des]);
1195 if (origin == stk) {
1197 printcard(stockcol, stockrow, stock);
1200 printcard(taloncol, talonrow, talon);
1213 int dlength, slength, i;
1214 struct cardtype *tempcard;
1216 for (i=tabrow; i<=length[sour]; i++)
1217 removecard(pilemap[sour], i);
1218 dlength = length[des] + 1;
1219 slength = length[sour];
1220 if (slength == tabrow)
1221 printcard(pilemap[des], dlength, tableau[sour]);
1223 while (slength != tabrow - 1) {
1224 tempcard = tableau[sour];
1225 for (i=1; i<=slength-tabrow; i++)
1226 tempcard = tempcard->next;
1227 printcard(pilemap[des], dlength, tempcard);
1234 * procedure to move from the tableau to the tableau
1240 struct cardtype *temp;
1242 if (notempty(tableau[sour])) {
1243 if (tabok(bottom[sour], des)) {
1244 tabprint(sour, des);
1245 temp = bottom[sour];
1247 if (bottom[des] == NIL)
1249 temp->next = tableau[des];
1250 tableau[des] = tableau[sour];
1251 tableau[sour] = NIL;
1252 length[des] = length[des] + (length[sour] - (tabrow - 1));
1253 length[sour] = tabrow - 1;
1261 * functions to see if the card can go onto the foundation
1265 struct cardtype *cp;
1267 if (found[let]->rank == King)
1268 if (cp->rank == Ace)
1272 else if (cp->rank - 1 == found[let]->rank)
1279 * function to determine if two cards are the same suit
1283 struct cardtype *cp;
1285 if (cp->suit == found[let]->suit)
1292 * procedure to move a card to the correct foundation pile
1295 movetofound(cp, source)
1296 struct cardtype **cp;
1300 if (notempty(*cp)) {
1302 if (found[tempbase] != NIL)
1303 if (rankhigher(*cp, tempbase)
1304 && samesuit(*cp, tempbase)) {
1307 else if (*cp == talon)
1311 transit(cp, &found[tempbase]);
1312 printcard(pilemap[tempbase],
1313 foundrow, found[tempbase]);
1315 if (mtforigin == stk) {
1317 printcard(stockcol, stockrow, stock);
1318 } else if (mtforigin == tal) {
1320 printcard(taloncol, talonrow, talon);
1322 removecard(pilemap[source], length[source]);
1327 this.wins += valuepercardup;
1328 game.wins += valuepercardup;
1329 total.wins += valuepercardup;
1336 } while ((tempbase != 4) && !mtfdone);
1343 * procedure to get a command
1346 getcmd(row, col, cp)
1355 printw("%-24s", cp);
1356 col += 1 + strlen(cp);
1360 ch = getch() & 0177;
1361 if (ch >= 'A' && ch <= 'Z')
1366 } else if (i >= 2 && ch != erasechar() && ch != killchar()) {
1367 if (ch != '\n' && ch != '\r' && ch != ' ')
1368 write(1, "\007", 1);
1369 } else if (ch == erasechar() && i > 0) {
1373 } else if (ch == killchar() && i > 0) {
1379 } else if (ch == '\032') { /* Control-Z */
1383 } else if (isprint(ch)) {
1388 } while (ch != '\n' && ch != '\r' && ch != ' ');
1394 * Suspend the game (shell escape if no process control on system)
1403 updatebettinginfo();
1407 lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1408 write(dbfd, (char *)&total, sizeof(total));
1410 kill(getpid(), SIGTSTP);
1416 * procedure to evaluate and make the specific moves
1422 char osrcpile, odestpile;
1429 if (talon == NIL && hand != NIL)
1431 if (cardsoff == 52) {
1434 } else if (!startedgame) {
1435 move(msgrow, msgcol);
1437 switch (34 - taloncnt - cinhand) {
1442 printw("One card used from talon ");
1445 printw("Two cards used from talon ");
1448 printw(">3< cards used from talon ");
1451 getcmd(moverow, movecol, "Move:");
1453 getcmd(moverow, movecol, "Move:");
1455 if (srcpile >= '1' && srcpile <= '4')
1456 source = (int) (srcpile - '1');
1457 if (destpile >= '1' && destpile <= '4')
1458 dest = (int) (destpile - '1');
1460 (srcpile == 't' || srcpile == 's' || srcpile == 'h' ||
1461 srcpile == '1' || srcpile == '2' || srcpile == '3' ||
1465 odestpile = destpile;
1466 if (status != BETTINGBOX)
1469 getcmd(moverow, movecol, "Inspect game?");
1470 } while (srcpile != 'y' && srcpile != 'n');
1471 if (srcpile == 'n') {
1474 this.inspection += costofinspection;
1475 game.inspection += costofinspection;
1476 total.inspection += costofinspection;
1478 destpile = odestpile;
1483 if (destpile == 'f' || destpile == 'F')
1484 movetofound(&talon, source);
1485 else if (destpile >= '1' && destpile <= '4')
1486 simpletableau(&talon, dest);
1491 if (destpile == 'f' || destpile == 'F')
1492 movetofound(&stock, source);
1493 else if (destpile >= '1' && destpile <= '4')
1494 simpletableau(&stock, dest);
1498 if (destpile != 't' && destpile != 'T') {
1506 if (status == BETTINGBOX) {
1508 getcmd(moverow, movecol,
1510 } while (srcpile != 'y' &&
1512 if (srcpile == 'n') {
1519 this.wins += valuepercardup * cardsoff;
1520 game.wins += valuepercardup * cardsoff;
1521 total.wins += valuepercardup * cardsoff;
1522 this.game += costofgame;
1523 game.game += costofgame;
1524 total.game += costofgame;
1532 printtopbettingbox();
1533 printbottombettingbox();
1534 status = BETTINGBOX;
1537 clearabovemovebox();
1538 clearbelowmovebox();
1542 printtopinstructions();
1543 printbottominstructions();
1544 status = INSTRUCTIONBOX;
1553 case '1': case '2': case '3': case '4':
1554 if (destpile == 'f' || destpile == 'F')
1555 movetofound(&tableau[source], source);
1556 else if (destpile >= '1' && destpile <= '4')
1557 tabtotab(source, dest);
1563 fndbase(&stock, stockcol, stockrow);
1564 fndbase(&talon, taloncol, talonrow);
1565 updatebettinginfo();
1569 char *basicinstructions[] = {
1570 "Here are brief instuctions to the game of Canfield:\n\n",
1571 " If you have never played solitaire before, it is recom-\n",
1572 "mended that you consult a solitaire instruction book. In\n",
1573 "Canfield, tableau cards may be built on each other downward\n",
1574 "in alternate colors. An entire pile must be moved as a unit\n",
1575 "in building. Top cards of the piles are available to be able\n",
1576 "to be played on foundations, but never into empty spaces.\n\n",
1577 " Spaces must be filled from the stock. The top card of\n",
1578 "the stock also is available to be played on foundations or\n",
1579 "built on tableau piles. After the stock is exhausted, ta-\n",
1580 "bleau spaces may be filled from the talon and the player may\n",
1581 "keep them open until he wishes to use them.\n\n",
1582 " Cards are dealt from the hand to the talon by threes\n",
1583 "and this repeats until there are no more cards in the hand\n",
1584 "or the player quits. To have cards dealt onto the talon the\n",
1585 "player types 'ht' for his move. Foundation base cards are\n",
1586 "also automatically moved to the foundation when they become\n",
1588 "push any key when you are finished: ",
1591 char *bettinginstructions[] = {
1592 " The rules for betting are somewhat less strict than\n",
1593 "those used in the official version of the game. The initial\n",
1594 "deal costs $13. You may quit at this point or inspect the\n",
1595 "game. Inspection costs $13 and allows you to make as many\n",
1596 "moves as is possible without moving any cards from your hand\n",
1597 "to the talon. (the initial deal places three cards on the\n",
1598 "talon; if all these cards are used, three more are made\n",
1599 "available) Finally, if the game seems interesting, you must\n",
1600 "pay the final installment of $26. At this point you are\n",
1601 "credited at the rate of $5 for each card on the foundation;\n",
1602 "as the game progresses you are credited with $5 for each\n",
1603 "card that is moved to the foundation. Each run through the\n",
1604 "hand after the first costs $5. The card counting feature\n",
1605 "costs $1 for each unknown card that is identified. If the\n",
1606 "information is toggled on, you are only charged for cards\n",
1607 "that became visible since it was last turned on. Thus the\n",
1608 "maximum cost of information is $34. Playing time is charged\n",
1609 "at a rate of $1 per minute.\n\n",
1610 "push any key when you are finished: ",
1614 * procedure to printout instructions
1621 move(originrow, origincol);
1622 printw("This is the game of solitaire called Canfield. Do\n");
1623 printw("you want instructions for the game?");
1625 getcmd(originrow + 3, origincol, "y or n?");
1626 } while (srcpile != 'y' && srcpile != 'n');
1630 for (cp = basicinstructions; *cp != 0; cp++)
1635 move(originrow, origincol);
1636 printw("Do you want instructions for betting?");
1638 getcmd(originrow + 2, origincol, "y or n?");
1639 } while (srcpile != 'y' && srcpile != 'n');
1643 for (cp = bettinginstructions; *cp != 0; cp++)
1650 * procedure to initialize the game
1664 i = lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1670 i = read(dbfd, (char *)&total, sizeof(total));
1679 * procedure to end the game
1686 if (cardsoff == 52) {
1687 getcmd(moverow, movecol, "Hit return to exit");
1690 move(originrow, origincol);
1691 printw("CONGRATULATIONS!\n");
1692 printw("You won the game. That is a feat to be proud of.\n");
1693 row = originrow + 5;
1696 move(msgrow, msgcol);
1697 printw("You got %d card", cardsoff);
1701 move(msgrow, msgcol);
1706 getcmd(row, col, "Play again (y or n)?");
1707 } while (srcpile != 'y' && srcpile != 'n');
1717 * procedure to clean up and exit
1724 total.thinktime += 1;
1726 updatebettinginfo();
1728 lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1729 write(dbfd, (char *)&total, sizeof(total));
1741 * Field an interrupt.
1747 move(msgrow, msgcol);
1748 printw("Really wish to quit? ");
1750 getcmd(moverow, movecol, "y or n?");
1751 } while (srcpile != 'y' && srcpile != 'n');
1755 signal(SIGINT, askquit);
1759 * Can you tell that this used to be a Pascal program?
1764 dbfd = open(_PATH_SCORE, O_RDWR);
1773 if (vec[2] >= MAXLOAD) {
1774 puts("The system load is too high. Try again later.");
1778 signal(SIGINT, askquit);
1779 signal(SIGHUP, cleanup);
1780 signal(SIGTERM, cleanup);
1800 exit (EXIT_FAILURE);