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
35 static const char copyright[] =
36 "@(#) Copyright (c) 1980, 1993\n\
37 The Regents of the University of California. All rights reserved.\n";
42 static char sccsid[] = "@(#)canfield.c 8.1 (Berkeley) 5/31/93";
44 static const char rcsid[] =
45 "$FreeBSD: src/games/canfield/canfield/canfield.c,v 1.11 1999/12/12 07:25:13 billf Exp $";
49 * The canfield program
52 * Originally written: Steve Levine
53 * Converted to use curses and debugged: Steve Feldman
54 * Card counting: Kirk McKusick and Mikey Olson
55 * User interface cleanups: Eric Allman and Kirk McKusick
56 * Betting by Kirk McKusick
59 #include <sys/types.h>
70 #include "pathnames.h"
101 #define handstatrow 21
102 #define handstatcol 7
103 #define talonstatrow 22
104 #define talonstatcol 7
105 #define stockstatrow 23
106 #define stockstatcol 7
126 #define INCRHAND(row, col) {\
128 if (row < ctoprow) {\
133 #define DECRHAND(row, col) {\
135 if (row > cbotrow) {\
148 struct cardtype *next;
151 #define NIL ((struct cardtype *) -1)
153 struct cardtype *deck[decksize];
154 struct cardtype cards[decksize];
155 struct cardtype *bottom[4], *found[4], *tableau[4];
156 struct cardtype *talon, *hand, *stock, *basecard;
158 int cardsoff, base, cinhand, taloncnt, stockcnt, timesthru;
159 char suitmap[4] = {spades, clubs, hearts, diamonds};
160 char colormap[4] = {black, black, red, red};
161 char pilemap[4] = {atabcol, btabcol, ctabcol, dtabcol};
162 char srcpile, destpile;
163 int mtforigin, tempbase;
164 int coldcol, cnewcol, coldrow, cnewrow;
166 bool mtfdone, Cflag = FALSE;
167 #define INSTRUCTIONBOX 1
170 int status = INSTRUCTIONBOX;
174 * Basic betting costs
176 #define costofhand 13
177 #define costofinspection 13
178 #define costofgame 26
179 #define costofrunthroughhand 5
180 #define costofinformation 1
181 #define secondsperdollar 60
182 #define maxtimecharge 3
183 #define valuepercardup 5
185 * Variables associated with betting
188 long hand; /* cost of dealing hand */
189 long inspection; /* cost of inspecting hand */
190 long game; /* cost of buying game */
191 long runs; /* cost of running through hands */
192 long information; /* cost of information */
193 long thinktime; /* cost of thinking time */
194 long wins; /* total winnings */
195 long worth; /* net worth after costs */
197 struct betinfo this, game, total;
198 bool startedgame = FALSE, infullgame = FALSE;
202 void askquit __P((int));
203 void cleanup __P((int));
204 void cleanupboard __P((void));
205 void clearabovemovebox __P((void));
206 void clearbelowmovebox __P((void));
207 void clearmsg __P((void));
208 void clearstat __P((void));
209 void destinerror __P((void));
210 bool diffcolor __P((struct cardtype *, struct cardtype *));
211 void dumberror __P((void));
212 bool finish __P((void));
213 void fndbase __P((struct cardtype **, int, int));
214 void getcmd __P((int, int, char *));
215 void initall __P((void));
216 void initdeck __P((struct cardtype *[]));
217 void initgame __P((void));
218 void instruct __P((void));
219 void makeboard __P((void));
220 void movebox __P((void));
221 void movecard __P((void));
222 void movetofound __P((struct cardtype **, int));
223 void movetotalon __P((void));
224 bool notempty __P((struct cardtype *));
225 void printbottombettingbox __P((void));
226 void printbottominstructions __P((void));
227 void printcard __P((int, int, struct cardtype *));
228 void printrank __P((int, int, struct cardtype *, bool));
229 void printtopbettingbox __P((void));
230 void printtopinstructions __P((void));
231 bool rankhigher __P((struct cardtype *, int));
232 bool ranklower __P((struct cardtype *, struct cardtype *));
233 void removecard __P((int, int));
234 bool samesuit __P((struct cardtype *, int));
235 void showcards __P((void));
236 void showstat __P((void));
237 void shuffle __P((struct cardtype *[]));
238 void simpletableau __P((struct cardtype **, int));
239 void startgame __P((void));
240 void suspend __P((void));
241 bool tabok __P((struct cardtype *, int));
242 void tabprint __P((int, int));
243 void tabtotab __P((int, int));
244 void transit __P((struct cardtype **, struct cardtype **));
245 void updatebettinginfo __P((void));
246 void usedstock __P((void));
247 void usedtalon __P((void));
250 * The following procedures print the board onto the screen using the
251 * addressible cursor. The end of these procedures will also be
252 * separated from the rest of the program.
254 * procedure to set the move command box
261 printtopbettingbox();
267 printtopinstructions();
270 move(moverow, boxcol);
272 move(msgrow, boxcol);
276 printbottombettingbox();
282 printbottominstructions();
289 * print directions above move box
292 printtopinstructions()
294 move(tboxrow, boxcol);
295 printw("*----------------------------------*");
296 move(tboxrow + 1, boxcol);
298 move(tboxrow + 2, boxcol);
299 printw("|s# = stock to tableau |");
300 move(tboxrow + 3, boxcol);
301 printw("|sf = stock to foundation |");
302 move(tboxrow + 4, boxcol);
303 printw("|t# = talon to tableau |");
304 move(tboxrow + 5, boxcol);
305 printw("|tf = talon to foundation |");
306 move(tboxrow + 6, boxcol);
307 printw("|## = tableau to tableau |");
308 move(tboxrow + 7, boxcol);
309 printw("|#f = tableau to foundation |");
310 move(tboxrow + 8, boxcol);
311 printw("|ht = hand to talon |");
312 move(tboxrow + 9, boxcol);
313 printw("|c = toggle card counting |");
314 move(tboxrow + 10, boxcol);
315 printw("|b = present betting information |");
316 move(tboxrow + 11, boxcol);
317 printw("|q = quit to end the game |");
318 move(tboxrow + 12, boxcol);
319 printw("|==================================|");
323 * Print the betting box.
329 move(tboxrow, boxcol);
330 printw("*----------------------------------*");
331 move(tboxrow + 1, boxcol);
332 printw("|Costs Hand Game Total |");
333 move(tboxrow + 2, boxcol);
335 move(tboxrow + 3, boxcol);
336 printw("| Inspections |");
337 move(tboxrow + 4, boxcol);
339 move(tboxrow + 5, boxcol);
341 move(tboxrow + 6, boxcol);
342 printw("| Information |");
343 move(tboxrow + 7, boxcol);
344 printw("| Think time |");
345 move(tboxrow + 8, boxcol);
346 printw("|Total Costs |");
347 move(tboxrow + 9, boxcol);
348 printw("|Winnings |");
349 move(tboxrow + 10, boxcol);
350 printw("|Net Worth |");
351 move(tboxrow + 11, boxcol);
353 move(tboxrow + 12, boxcol);
354 printw("|==================================|");
358 * clear info above move box
365 for (i = 0; i <= 11; i++) {
366 move(tboxrow + i, boxcol);
369 move(tboxrow + 12, boxcol);
370 printw("*----------------------------------*");
374 * print instructions below move box
377 printbottominstructions()
379 move(bboxrow, boxcol);
380 printw("|Replace # with the number of the |");
381 move(bboxrow + 1, boxcol);
382 printw("|tableau you want. |");
383 move(bboxrow + 2, boxcol);
384 printw("*----------------------------------*");
388 * print betting information below move box
391 printbottombettingbox()
393 move(bboxrow, boxcol);
394 printw("|x = toggle information box |");
395 move(bboxrow + 1, boxcol);
396 printw("|i = list playing instructions |");
397 move(bboxrow + 2, boxcol);
398 printw("*----------------------------------*");
402 * clear info below move box
409 move(bboxrow, boxcol);
410 printw("*----------------------------------*");
411 for (i = 1; i <= 2; i++) {
412 move(bboxrow + i, boxcol);
418 * procedure to put the board on the screen using addressable cursor
425 move(titlerow, titlecol);
426 printw("=-> CANFIELD <-=");
427 move(fttlrow, fttlcol);
428 printw("foundation");
429 move(foundrow - 1, fttlcol);
430 printw("=---= =---= =---= =---=");
431 move(foundrow, fttlcol);
432 printw("| | | | | | | |");
433 move(foundrow + 1, fttlcol);
434 printw("=---= =---= =---= =---=");
435 move(ottlrow, sidecol);
436 printw("stock tableau");
437 move(stockrow - 1, sidecol);
439 move(stockrow, sidecol);
441 move(stockrow + 1, sidecol);
443 move(talonrow - 2, sidecol);
445 move(talonrow - 1, sidecol);
447 move(talonrow, sidecol);
449 move(talonrow + 1, sidecol);
451 move(tabrow - 1, atabcol);
452 printw("-1- -2- -3- -4-");
457 * clean up the board for another game
463 struct cardtype *ptr;
468 for(ptr = stock, row = stockrow;
470 ptr = ptr->next, row++) {
476 move(stockrow + 1, sidecol);
478 move(talonrow - 2, sidecol);
480 move(talonrow - 1, sidecol);
482 move(talonrow + 1, sidecol);
485 move(stockrow, sidecol);
487 move(talonrow, sidecol);
489 move(foundrow, fttlcol);
490 printw("| | | | | | | |");
491 for (cnt = 0; cnt < 4; cnt++) {
506 for(ptr = tableau[cnt], row = tabrow;
508 ptr = ptr->next, row++)
509 removecard(col, row);
514 * procedure to create a deck of cards
518 struct cardtype *deck[];
526 for (scnt=0; scnt<4; scnt++) {
528 for (r=Ace; r<=King; r++) {
532 cards[i].color = colormap[scnt];
540 * procedure to shuffle the deck
544 struct cardtype *deck[];
547 struct cardtype *temp;
549 for (i=0; i<decksize; i++) {
550 deck[i]->visible = FALSE;
551 deck[i]->paid = FALSE;
553 for (i = decksize-1; i>=0; i--) {
554 j = random() % decksize;
564 * procedure to remove the card from the board
574 * procedure to print the cards on the board
577 printrank(a, b, cp, inverse)
587 case 2: case 3: case 4: case 5: case 6: case 7:
588 case 8: case 9: case 10:
589 printw("%d", cp->rank);
608 * procedure to print out a card
617 else if (cp->visible == FALSE) {
621 bool inverse = (cp->suit == 'd' || cp->suit == 'h');
623 printrank(a, b, cp, inverse);
633 * procedure to move the top card from one location to the top
634 * of another location. The pointers always point to the top
638 transit(source, dest)
639 struct cardtype **source, **dest;
641 struct cardtype *temp;
644 *source = (*source)->next;
650 * Procedure to set the cards on the foundation base when available.
651 * Note that it is only called on a foundation pile at the beginning of
652 * the game, so the pile will have exactly one card in it.
655 fndbase(cp, column, row)
656 struct cardtype **cp;
662 if ((*cp)->rank == basecard->rank) {
664 printcard(pilemap[base], foundrow, *cp);
665 if (*cp == tableau[0])
666 length[0] = length[0] - 1;
667 if (*cp == tableau[1])
668 length[1] = length[1] - 1;
669 if (*cp == tableau[2])
670 length[2] = length[2] - 1;
671 if (*cp == tableau[3])
672 length[3] = length[3] - 1;
673 transit(cp, &found[base]);
679 printcard(column, row, *cp);
682 removecard(column, row);
687 this.wins += valuepercardup;
688 game.wins += valuepercardup;
689 total.wins += valuepercardup;
693 } while (nomore == FALSE);
697 * procedure to initialize the things necessary for the game
704 for (i=0; i<18; i++) {
705 deck[i]->visible = TRUE;
706 deck[i]->paid = TRUE;
710 for (i=12; i>=1; i--)
711 deck[i]->next = deck[i - 1];
714 deck[13]->next = NIL;
718 for (i=14; i<18; i++) {
719 tableau[i - 14] = deck[i];
722 for (i=0; i<4; i++) {
723 bottom[i] = tableau[i];
727 for (i=18; i<decksize-1; i++)
728 deck[i]->next = deck[i + 1];
729 deck[decksize-1]->next = NIL;
739 cnewcol = cinitcol + cwidthcol;
743 * procedure to print the beginning cards and to start each game
752 this.hand = costofhand;
753 game.hand += costofhand;
754 total.hand += costofhand;
758 this.information = 0;
763 printcard(foundcol, foundrow, found[0]);
764 printcard(stockcol, stockrow, stock);
765 printcard(atabcol, tabrow, tableau[0]);
766 printcard(btabcol, tabrow, tableau[1]);
767 printcard(ctabcol, tabrow, tableau[2]);
768 printcard(dtabcol, tabrow, tableau[3]);
769 printcard(taloncol, talonrow, talon);
770 move(foundrow - 2, basecol);
772 move(foundrow - 1, basecol);
774 printrank(basecol, foundrow, found[0], 0);
776 fndbase(&tableau[j], pilemap[j], tabrow);
777 fndbase(&stock, stockcol, stockrow);
778 showstat(); /* show card counting info to cheaters */
784 * procedure to clear the message printed from an error
791 if (errmsg == TRUE) {
793 move(msgrow, msgcol);
801 * procedure to print an error message if the move is not listed
807 move(msgrow, msgcol);
808 printw("Not a proper move ");
812 * procedure to print an error message if the move is not possible
818 move(msgrow, msgcol);
819 printw("Error: Can't move there");
823 * function to see if the source has cards in it
831 move(msgrow, msgcol);
832 printw("Error: no cards to move");
839 * function to see if the rank of one card is less than another
843 struct cardtype *cp1, *cp2;
845 if (cp2->rank == Ace)
846 if (cp1->rank == King)
850 else if (cp1->rank + 1 == cp2->rank)
857 * function to check the cardcolor for moving to a tableau
861 struct cardtype *cp1, *cp2;
863 if (cp1->color == cp2->color)
870 * function to see if the card can move to the tableau
876 if ((cp == stock) && (tableau[des] == NIL))
878 else if (tableau[des] == NIL)
880 cp != bottom[0] && cp != bottom[1] &&
881 cp != bottom[2] && cp != bottom[3])
885 else if (ranklower(cp, tableau[des]) && diffcolor(cp, tableau[des]))
892 * procedure to turn the cards onto the talon from the deck
899 if (cinhand <= 3 && cinhand > 0) {
900 move(msgrow, msgcol);
901 printw("Hand is now empty ");
905 else if (cinhand > 0)
907 else if (talon != NIL) {
910 move(msgrow, msgcol);
911 if (timesthru != 4) {
912 printw("Talon is now the new hand");
913 this.runs += costofrunthroughhand;
914 game.runs += costofrunthroughhand;
915 total.runs += costofrunthroughhand;
916 while (talon != NIL) {
917 transit(&talon, &hand);
928 cnewcol = cinitcol + cwidthcol;
934 printw("I believe you have lost");
940 move(msgrow, msgcol);
941 printw("Talon and hand are empty");
944 for (i=0; i<fin; i++) {
945 transit(&hand, &talon);
946 INCRHAND(cnewrow, cnewcol);
947 INCRHAND(coldrow, coldcol);
948 removecard(cnewcol, cnewrow);
950 talon->visible = TRUE;
952 if (talon->paid == FALSE && talon->visible == TRUE) {
953 this.information += costofinformation;
954 game.information += costofinformation;
955 total.information += costofinformation;
958 printcard(coldcol, coldrow, talon);
962 printcard(taloncol, talonrow, talon);
966 move(handstatrow, handstatcol);
967 printw("%3d", cinhand);
968 move(talonstatrow, talonstatcol);
969 printw("%3d", taloncnt);
971 fndbase(&talon, taloncol, talonrow);
977 * procedure to print card counting info on screen
983 struct cardtype *ptr;
987 move(talonstatrow, talonstatcol - 7);
988 printw("Talon: %3d", taloncnt);
989 move(handstatrow, handstatcol - 7);
990 printw("Hand: %3d", cinhand);
991 move(stockstatrow, stockstatcol - 7);
992 printw("Stock: %3d", stockcnt);
993 for ( row = coldrow, col = coldcol, ptr = talon;
996 if (ptr->paid == FALSE && ptr->visible == TRUE) {
998 this.information += costofinformation;
999 game.information += costofinformation;
1000 total.information += costofinformation;
1002 printcard(col, row, ptr);
1005 for ( row = cnewrow, col = cnewcol, ptr = hand;
1008 if (ptr->paid == FALSE && ptr->visible == TRUE) {
1010 this.information += costofinformation;
1011 game.information += costofinformation;
1012 total.information += costofinformation;
1015 printcard(col, row, ptr);
1020 * procedure to clear card counting info from screen
1027 move(talonstatrow, talonstatcol - 7);
1029 move(handstatrow, handstatcol - 7);
1031 move(stockstatrow, stockstatcol - 7);
1033 for ( row = ctoprow ; row <= cbotrow ; row++ ) {
1034 move(row, cinitcol);
1035 printw("%56s", " ");
1040 * procedure to update card counting base
1045 removecard(coldcol, coldrow);
1046 DECRHAND(coldrow, coldcol);
1047 if (talon != NIL && (talon->visible == FALSE)) {
1048 talon->visible = TRUE;
1050 this.information += costofinformation;
1051 game.information += costofinformation;
1052 total.information += costofinformation;
1054 printcard(coldcol, coldrow, talon);
1059 move(talonstatrow, talonstatcol);
1060 printw("%3d", taloncnt);
1065 * procedure to update stock card counting base
1072 move(stockstatrow, stockstatcol);
1073 printw("%3d", stockcnt);
1078 * let 'em know how they lost!
1083 struct cardtype *ptr;
1086 if (!Cflag || cardsoff == 52)
1088 for (ptr = talon; ptr != NIL; ptr = ptr->next) {
1089 ptr->visible = TRUE;
1092 for (ptr = hand; ptr != NIL; ptr = ptr->next) {
1093 ptr->visible = TRUE;
1097 move(stockrow + 1, sidecol);
1099 move(talonrow - 2, sidecol);
1101 move(talonrow - 1, sidecol);
1103 move(talonrow, sidecol);
1105 move(talonrow + 1, sidecol);
1107 for (ptr = stock, row = stockrow; ptr != NIL; ptr = ptr->next, row++) {
1108 move(row, stockcol - 1);
1110 printcard(stockcol, row, ptr);
1113 move(row, stockcol - 1);
1117 move(handstatrow, handstatcol - 7);
1119 move(row, stockcol - 1);
1121 if ( cardsoff == 52 )
1122 getcmd(moverow, movecol, "Hit return to exit");
1126 * procedure to update the betting values
1131 long thiscosts, gamecosts, totalcosts;
1132 double thisreturn, gamereturn, totalreturn;
1137 dollars = (now - acctstart) / secondsperdollar;
1139 acctstart += dollars * secondsperdollar;
1140 if (dollars > maxtimecharge)
1141 dollars = maxtimecharge;
1142 this.thinktime += dollars;
1143 game.thinktime += dollars;
1144 total.thinktime += dollars;
1146 thiscosts = this.hand + this.inspection + this.game +
1147 this.runs + this.information + this.thinktime;
1148 gamecosts = game.hand + game.inspection + game.game +
1149 game.runs + game.information + game.thinktime;
1150 totalcosts = total.hand + total.inspection + total.game +
1151 total.runs + total.information + total.thinktime;
1152 this.worth = this.wins - thiscosts;
1153 game.worth = game.wins - gamecosts;
1154 total.worth = total.wins - totalcosts;
1155 thisreturn = ((double)this.wins / (double)thiscosts - 1.0) * 100.0;
1156 gamereturn = ((double)game.wins / (double)gamecosts - 1.0) * 100.0;
1157 totalreturn = ((double)total.wins / (double)totalcosts - 1.0) * 100.0;
1158 if (status != BETTINGBOX)
1160 move(tboxrow + 2, boxcol + 13);
1161 printw("%4d%8d%9d", this.hand, game.hand, total.hand);
1162 move(tboxrow + 3, boxcol + 13);
1163 printw("%4d%8d%9d", this.inspection, game.inspection, total.inspection);
1164 move(tboxrow + 4, boxcol + 13);
1165 printw("%4d%8d%9d", this.game, game.game, total.game);
1166 move(tboxrow + 5, boxcol + 13);
1167 printw("%4d%8d%9d", this.runs, game.runs, total.runs);
1168 move(tboxrow + 6, boxcol + 13);
1169 printw("%4d%8d%9d", this.information, game.information,
1171 move(tboxrow + 7, boxcol + 13);
1172 printw("%4d%8d%9d", this.thinktime, game.thinktime, total.thinktime);
1173 move(tboxrow + 8, boxcol + 13);
1174 printw("%4d%8d%9d", thiscosts, gamecosts, totalcosts);
1175 move(tboxrow + 9, boxcol + 13);
1176 printw("%4d%8d%9d", this.wins, game.wins, total.wins);
1177 move(tboxrow + 10, boxcol + 13);
1178 printw("%4d%8d%9d", this.worth, game.worth, total.worth);
1179 move(tboxrow + 11, boxcol + 13);
1180 printw("%4.0f%%%7.1f%%%8.1f%%", thisreturn, gamereturn, totalreturn);
1184 * procedure to move a card from the stock or talon to the tableau
1187 simpletableau(cp, des)
1188 struct cardtype **cp;
1192 if (notempty(*cp)) {
1193 if (tabok(*cp, des)) {
1198 if (tableau[des] == NIL)
1200 transit(cp, &tableau[des]);
1202 printcard(pilemap[des], length[des], tableau[des]);
1204 if (origin == stk) {
1206 printcard(stockcol, stockrow, stock);
1209 printcard(taloncol, talonrow, talon);
1222 int dlength, slength, i;
1223 struct cardtype *tempcard;
1225 for (i=tabrow; i<=length[sour]; i++)
1226 removecard(pilemap[sour], i);
1227 dlength = length[des] + 1;
1228 slength = length[sour];
1229 if (slength == tabrow)
1230 printcard(pilemap[des], dlength, tableau[sour]);
1232 while (slength != tabrow - 1) {
1233 tempcard = tableau[sour];
1234 for (i=1; i<=slength-tabrow; i++)
1235 tempcard = tempcard->next;
1236 printcard(pilemap[des], dlength, tempcard);
1243 * procedure to move from the tableau to the tableau
1249 struct cardtype *temp;
1251 if (notempty(tableau[sour])) {
1252 if (tabok(bottom[sour], des)) {
1253 tabprint(sour, des);
1254 temp = bottom[sour];
1256 if (bottom[des] == NIL)
1258 temp->next = tableau[des];
1259 tableau[des] = tableau[sour];
1260 tableau[sour] = NIL;
1261 length[des] = length[des] + (length[sour] - (tabrow - 1));
1262 length[sour] = tabrow - 1;
1270 * functions to see if the card can go onto the foundation
1274 struct cardtype *cp;
1276 if (found[let]->rank == King)
1277 if (cp->rank == Ace)
1281 else if (cp->rank - 1 == found[let]->rank)
1288 * function to determine if two cards are the same suit
1292 struct cardtype *cp;
1294 if (cp->suit == found[let]->suit)
1301 * procedure to move a card to the correct foundation pile
1304 movetofound(cp, source)
1305 struct cardtype **cp;
1309 if (notempty(*cp)) {
1311 if (found[tempbase] != NIL)
1312 if (rankhigher(*cp, tempbase)
1313 && samesuit(*cp, tempbase)) {
1316 else if (*cp == talon)
1320 transit(cp, &found[tempbase]);
1321 printcard(pilemap[tempbase],
1322 foundrow, found[tempbase]);
1324 if (mtforigin == stk) {
1326 printcard(stockcol, stockrow, stock);
1327 } else if (mtforigin == tal) {
1329 printcard(taloncol, talonrow, talon);
1331 removecard(pilemap[source], length[source]);
1336 this.wins += valuepercardup;
1337 game.wins += valuepercardup;
1338 total.wins += valuepercardup;
1345 } while ((tempbase != 4) && !mtfdone);
1352 * procedure to get a command
1355 getcmd(row, col, cp)
1364 printw("%-24s", cp);
1365 col += 1 + strlen(cp);
1369 ch = getch() & 0177;
1370 if (ch >= 'A' && ch <= 'Z')
1375 } else if (i >= 2 && ch != erasechar() && ch != killchar()) {
1376 if (ch != '\n' && ch != '\r' && ch != ' ')
1377 write(1, "\007", 1);
1378 } else if (ch == erasechar() && i > 0) {
1382 } else if (ch == killchar() && i > 0) {
1388 } else if (ch == '\032') { /* Control-Z */
1392 } else if (isprint(ch)) {
1397 } while (ch != '\n' && ch != '\r' && ch != ' ');
1403 * Suspend the game (shell escape if no process control on system)
1412 updatebettinginfo();
1416 lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1417 write(dbfd, (char *)&total, sizeof(total));
1419 kill(getpid(), SIGTSTP);
1425 * procedure to evaluate and make the specific moves
1431 char osrcpile, odestpile;
1438 if (talon == NIL && hand != NIL)
1440 if (cardsoff == 52) {
1443 } else if (!startedgame) {
1444 move(msgrow, msgcol);
1446 switch (34 - taloncnt - cinhand) {
1451 printw("One card used from talon ");
1454 printw("Two cards used from talon ");
1457 printw(">3< cards used from talon ");
1460 getcmd(moverow, movecol, "Move:");
1462 getcmd(moverow, movecol, "Move:");
1464 if (srcpile >= '1' && srcpile <= '4')
1465 source = (int) (srcpile - '1');
1466 if (destpile >= '1' && destpile <= '4')
1467 dest = (int) (destpile - '1');
1469 (srcpile == 't' || srcpile == 's' || srcpile == 'h' ||
1470 srcpile == '1' || srcpile == '2' || srcpile == '3' ||
1474 odestpile = destpile;
1475 if (status != BETTINGBOX)
1478 getcmd(moverow, movecol, "Inspect game?");
1479 } while (srcpile != 'y' && srcpile != 'n');
1480 if (srcpile == 'n') {
1483 this.inspection += costofinspection;
1484 game.inspection += costofinspection;
1485 total.inspection += costofinspection;
1487 destpile = odestpile;
1492 if (destpile == 'f' || destpile == 'F')
1493 movetofound(&talon, source);
1494 else if (destpile >= '1' && destpile <= '4')
1495 simpletableau(&talon, dest);
1500 if (destpile == 'f' || destpile == 'F')
1501 movetofound(&stock, source);
1502 else if (destpile >= '1' && destpile <= '4')
1503 simpletableau(&stock, dest);
1507 if (destpile != 't' && destpile != 'T') {
1515 if (status == BETTINGBOX) {
1517 getcmd(moverow, movecol,
1519 } while (srcpile != 'y' &&
1521 if (srcpile == 'n') {
1528 this.wins += valuepercardup * cardsoff;
1529 game.wins += valuepercardup * cardsoff;
1530 total.wins += valuepercardup * cardsoff;
1531 this.game += costofgame;
1532 game.game += costofgame;
1533 total.game += costofgame;
1541 printtopbettingbox();
1542 printbottombettingbox();
1543 status = BETTINGBOX;
1546 clearabovemovebox();
1547 clearbelowmovebox();
1551 printtopinstructions();
1552 printbottominstructions();
1553 status = INSTRUCTIONBOX;
1562 case '1': case '2': case '3': case '4':
1563 if (destpile == 'f' || destpile == 'F')
1564 movetofound(&tableau[source], source);
1565 else if (destpile >= '1' && destpile <= '4')
1566 tabtotab(source, dest);
1572 fndbase(&stock, stockcol, stockrow);
1573 fndbase(&talon, taloncol, talonrow);
1574 updatebettinginfo();
1578 char *basicinstructions[] = {
1579 "Here are brief instuctions to the game of Canfield:\n\n",
1580 " If you have never played solitaire before, it is recom-\n",
1581 "mended that you consult a solitaire instruction book. In\n",
1582 "Canfield, tableau cards may be built on each other downward\n",
1583 "in alternate colors. An entire pile must be moved as a unit\n",
1584 "in building. Top cards of the piles are available to be able\n",
1585 "to be played on foundations, but never into empty spaces.\n\n",
1586 " Spaces must be filled from the stock. The top card of\n",
1587 "the stock also is available to be played on foundations or\n",
1588 "built on tableau piles. After the stock is exhausted, ta-\n",
1589 "bleau spaces may be filled from the talon and the player may\n",
1590 "keep them open until he wishes to use them.\n\n",
1591 " Cards are dealt from the hand to the talon by threes\n",
1592 "and this repeats until there are no more cards in the hand\n",
1593 "or the player quits. To have cards dealt onto the talon the\n",
1594 "player types 'ht' for his move. Foundation base cards are\n",
1595 "also automatically moved to the foundation when they become\n",
1597 "push any key when you are finished: ",
1600 char *bettinginstructions[] = {
1601 " The rules for betting are somewhat less strict than\n",
1602 "those used in the official version of the game. The initial\n",
1603 "deal costs $13. You may quit at this point or inspect the\n",
1604 "game. Inspection costs $13 and allows you to make as many\n",
1605 "moves as is possible without moving any cards from your hand\n",
1606 "to the talon. (the initial deal places three cards on the\n",
1607 "talon; if all these cards are used, three more are made\n",
1608 "available) Finally, if the game seems interesting, you must\n",
1609 "pay the final installment of $26. At this point you are\n",
1610 "credited at the rate of $5 for each card on the foundation;\n",
1611 "as the game progresses you are credited with $5 for each\n",
1612 "card that is moved to the foundation. Each run through the\n",
1613 "hand after the first costs $5. The card counting feature\n",
1614 "costs $1 for each unknown card that is identified. If the\n",
1615 "information is toggled on, you are only charged for cards\n",
1616 "that became visible since it was last turned on. Thus the\n",
1617 "maximum cost of information is $34. Playing time is charged\n",
1618 "at a rate of $1 per minute.\n\n",
1619 "push any key when you are finished: ",
1623 * procedure to printout instructions
1630 move(originrow, origincol);
1631 printw("This is the game of solitaire called Canfield. Do\n");
1632 printw("you want instructions for the game?");
1634 getcmd(originrow + 3, origincol, "y or n?");
1635 } while (srcpile != 'y' && srcpile != 'n');
1639 for (cp = basicinstructions; *cp != 0; cp++)
1644 move(originrow, origincol);
1645 printw("Do you want instructions for betting?");
1647 getcmd(originrow + 2, origincol, "y or n?");
1648 } while (srcpile != 'y' && srcpile != 'n');
1652 for (cp = bettinginstructions; *cp != 0; cp++)
1659 * procedure to initialize the game
1673 i = lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1679 i = read(dbfd, (char *)&total, sizeof(total));
1688 * procedure to end the game
1695 if (cardsoff == 52) {
1696 getcmd(moverow, movecol, "Hit return to exit");
1699 move(originrow, origincol);
1700 printw("CONGRATULATIONS!\n");
1701 printw("You won the game. That is a feat to be proud of.\n");
1702 row = originrow + 5;
1705 move(msgrow, msgcol);
1706 printw("You got %d card", cardsoff);
1710 move(msgrow, msgcol);
1715 getcmd(row, col, "Play again (y or n)?");
1716 } while (srcpile != 'y' && srcpile != 'n');
1726 * procedure to clean up and exit
1733 total.thinktime += 1;
1735 updatebettinginfo();
1737 lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1738 write(dbfd, (char *)&total, sizeof(total));
1750 * Field an interrupt.
1756 move(msgrow, msgcol);
1757 printw("Really wish to quit? ");
1759 getcmd(moverow, movecol, "y or n?");
1760 } while (srcpile != 'y' && srcpile != 'n');
1764 signal(SIGINT, askquit);
1768 * Can you tell that this used to be a Pascal program?
1773 dbfd = open(_PATH_SCORE, O_RDWR);
1782 if (vec[2] >= MAXLOAD) {
1783 puts("The system load is too high. Try again later.");
1787 signal(SIGINT, askquit);
1788 signal(SIGHUP, cleanup);
1789 signal(SIGTERM, cleanup);
1809 exit (EXIT_FAILURE);