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.4 2005/11/19 09:50:30 swildner 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>
60 #include "pathnames.h"
91 #define handstatrow 21
93 #define talonstatrow 22
94 #define talonstatcol 7
95 #define stockstatrow 23
96 #define stockstatcol 7
116 #define INCRHAND(row, col) {\
118 if (row < ctoprow) {\
123 #define DECRHAND(row, col) {\
125 if (row > cbotrow) {\
138 struct cardtype *next;
141 #define NIL ((struct cardtype *) -1)
143 struct cardtype *deck[decksize];
144 struct cardtype cards[decksize];
145 struct cardtype *bottom[4], *found[4], *tableau[4];
146 struct cardtype *talon, *hand, *stock, *basecard;
148 int cardsoff, base, cinhand, taloncnt, stockcnt, timesthru;
149 char suitmap[4] = {spades, clubs, hearts, diamonds};
150 char colormap[4] = {black, black, red, red};
151 char pilemap[4] = {atabcol, btabcol, ctabcol, dtabcol};
152 char srcpile, destpile;
153 int mtforigin, tempbase;
154 int coldcol, cnewcol, coldrow, cnewrow;
156 bool mtfdone, Cflag = FALSE;
157 #define INSTRUCTIONBOX 1
160 int status = INSTRUCTIONBOX;
164 * Basic betting costs
166 #define costofhand 13
167 #define costofinspection 13
168 #define costofgame 26
169 #define costofrunthroughhand 5
170 #define costofinformation 1
171 #define secondsperdollar 60
172 #define maxtimecharge 3
173 #define valuepercardup 5
175 * Variables associated with betting
178 long hand; /* cost of dealing hand */
179 long inspection; /* cost of inspecting hand */
180 long game; /* cost of buying game */
181 long runs; /* cost of running through hands */
182 long information; /* cost of information */
183 long thinktime; /* cost of thinking time */
184 long wins; /* total winnings */
185 long worth; /* net worth after costs */
187 struct betinfo this, game, total;
188 bool startedgame = FALSE, infullgame = FALSE;
192 static void askquit(int);
193 static void cleanup(int);
194 static void cleanupboard(void);
195 static void clearabovemovebox(void);
196 static void clearbelowmovebox(void);
197 static void clearmsg(void);
198 static void clearstat(void);
199 static void destinerror(void);
200 static bool diffcolor(struct cardtype *, struct cardtype *);
201 static void dumberror(void);
202 static bool finish(void);
203 static void fndbase(struct cardtype **, int, int);
204 static void getcmd(int, int, const char *);
205 static void initall(void);
206 static void initdeck(struct cardtype **);
207 static void initgame(void);
208 static void instruct(void);
209 static void makeboard(void);
210 static void movebox(void);
211 static void movecard(void);
212 static void movetofound(struct cardtype **, int);
213 static void movetotalon(void);
214 static bool notempty(struct cardtype *);
215 static void printbottombettingbox(void);
216 static void printbottominstructions(void);
217 static void printcard(int, int, struct cardtype *);
218 static void printrank(int, int, struct cardtype *, bool);
219 static void printtopbettingbox(void);
220 static void printtopinstructions(void);
221 static bool rankhigher(struct cardtype *, int);
222 static bool ranklower(struct cardtype *, struct cardtype *);
223 static void removecard(int, int);
224 static bool samesuit(struct cardtype *, int);
225 static void showcards(void);
226 static void showstat(void);
227 static void shuffle(struct cardtype **);
228 static void simpletableau(struct cardtype **, int);
229 static void startgame(void);
230 static void suspend(void);
231 static bool tabok(struct cardtype *, int);
232 static void tabprint(int, int);
233 static void tabtotab(int, int);
234 static void transit(struct cardtype **, struct cardtype **);
235 static void updatebettinginfo(void);
236 static void usedstock(void);
237 static void usedtalon(void);
240 * The following procedures print the board onto the screen using the
241 * addressible cursor. The end of these procedures will also be
242 * separated from the rest of the program.
244 * procedure to set the move command box
251 printtopbettingbox();
257 printtopinstructions();
260 move(moverow, boxcol);
262 move(msgrow, boxcol);
266 printbottombettingbox();
272 printbottominstructions();
279 * print directions above move box
282 printtopinstructions(void)
284 move(tboxrow, boxcol);
285 printw("*----------------------------------*");
286 move(tboxrow + 1, boxcol);
288 move(tboxrow + 2, boxcol);
289 printw("|s# = stock to tableau |");
290 move(tboxrow + 3, boxcol);
291 printw("|sf = stock to foundation |");
292 move(tboxrow + 4, boxcol);
293 printw("|t# = talon to tableau |");
294 move(tboxrow + 5, boxcol);
295 printw("|tf = talon to foundation |");
296 move(tboxrow + 6, boxcol);
297 printw("|## = tableau to tableau |");
298 move(tboxrow + 7, boxcol);
299 printw("|#f = tableau to foundation |");
300 move(tboxrow + 8, boxcol);
301 printw("|ht = hand to talon |");
302 move(tboxrow + 9, boxcol);
303 printw("|c = toggle card counting |");
304 move(tboxrow + 10, boxcol);
305 printw("|b = present betting information |");
306 move(tboxrow + 11, boxcol);
307 printw("|q = quit to end the game |");
308 move(tboxrow + 12, boxcol);
309 printw("|==================================|");
313 * Print the betting box.
316 printtopbettingbox(void)
319 move(tboxrow, boxcol);
320 printw("*----------------------------------*");
321 move(tboxrow + 1, boxcol);
322 printw("|Costs Hand Game Total |");
323 move(tboxrow + 2, boxcol);
325 move(tboxrow + 3, boxcol);
326 printw("| Inspections |");
327 move(tboxrow + 4, boxcol);
329 move(tboxrow + 5, boxcol);
331 move(tboxrow + 6, boxcol);
332 printw("| Information |");
333 move(tboxrow + 7, boxcol);
334 printw("| Think time |");
335 move(tboxrow + 8, boxcol);
336 printw("|Total Costs |");
337 move(tboxrow + 9, boxcol);
338 printw("|Winnings |");
339 move(tboxrow + 10, boxcol);
340 printw("|Net Worth |");
341 move(tboxrow + 11, boxcol);
343 move(tboxrow + 12, boxcol);
344 printw("|==================================|");
348 * clear info above move box
351 clearabovemovebox(void)
355 for (i = 0; i <= 11; i++) {
356 move(tboxrow + i, boxcol);
359 move(tboxrow + 12, boxcol);
360 printw("*----------------------------------*");
364 * print instructions below move box
367 printbottominstructions(void)
369 move(bboxrow, boxcol);
370 printw("|Replace # with the number of the |");
371 move(bboxrow + 1, boxcol);
372 printw("|tableau you want. |");
373 move(bboxrow + 2, boxcol);
374 printw("*----------------------------------*");
378 * print betting information below move box
381 printbottombettingbox(void)
383 move(bboxrow, boxcol);
384 printw("|x = toggle information box |");
385 move(bboxrow + 1, boxcol);
386 printw("|i = list playing instructions |");
387 move(bboxrow + 2, boxcol);
388 printw("*----------------------------------*");
392 * clear info below move box
395 clearbelowmovebox(void)
399 move(bboxrow, boxcol);
400 printw("*----------------------------------*");
401 for (i = 1; i <= 2; i++) {
402 move(bboxrow + i, boxcol);
408 * procedure to put the board on the screen using addressable cursor
415 move(titlerow, titlecol);
416 printw("=-> CANFIELD <-=");
417 move(fttlrow, fttlcol);
418 printw("foundation");
419 move(foundrow - 1, fttlcol);
420 printw("=---= =---= =---= =---=");
421 move(foundrow, fttlcol);
422 printw("| | | | | | | |");
423 move(foundrow + 1, fttlcol);
424 printw("=---= =---= =---= =---=");
425 move(ottlrow, sidecol);
426 printw("stock tableau");
427 move(stockrow - 1, sidecol);
429 move(stockrow, sidecol);
431 move(stockrow + 1, sidecol);
433 move(talonrow - 2, sidecol);
435 move(talonrow - 1, sidecol);
437 move(talonrow, sidecol);
439 move(talonrow + 1, sidecol);
441 move(tabrow - 1, atabcol);
442 printw("-1- -2- -3- -4-");
447 * clean up the board for another game
453 struct cardtype *ptr;
458 for(ptr = stock, row = stockrow;
460 ptr = ptr->next, row++) {
466 move(stockrow + 1, sidecol);
468 move(talonrow - 2, sidecol);
470 move(talonrow - 1, sidecol);
472 move(talonrow + 1, sidecol);
475 move(stockrow, sidecol);
477 move(talonrow, sidecol);
479 move(foundrow, fttlcol);
480 printw("| | | | | | | |");
481 for (cnt = 0; cnt < 4; cnt++) {
496 for(ptr = tableau[cnt], row = tabrow;
498 ptr = ptr->next, row++)
499 removecard(col, row);
504 * procedure to create a deck of cards
507 initdeck(struct cardtype **ldeck)
515 for (scnt=0; scnt<4; scnt++) {
517 for (r=Ace; r<=King; r++) {
518 ldeck[i] = &cards[i];
521 cards[i].color = colormap[scnt];
529 * procedure to shuffle the deck
532 shuffle(struct cardtype **ldeck)
535 struct cardtype *temp;
537 for (i=0; i<decksize; i++) {
538 ldeck[i]->visible = FALSE;
539 ldeck[i]->paid = FALSE;
541 for (i = decksize-1; i>=0; i--) {
542 j = random() % decksize;
552 * procedure to remove the card from the board
555 removecard(int a, int b)
562 * procedure to print the cards on the board
565 printrank(int a, int b, struct cardtype *cp, bool inverse)
573 case 2: case 3: case 4: case 5: case 6: case 7:
574 case 8: case 9: case 10:
575 printw("%d", cp->rank);
594 * procedure to print out a card
597 printcard(int a, int b, struct cardtype *cp)
601 else if (cp->visible == FALSE) {
605 bool inverse = (cp->suit == 'd' || cp->suit == 'h');
607 printrank(a, b, cp, inverse);
617 * procedure to move the top card from one location to the top
618 * of another location. The pointers always point to the top
622 transit(struct cardtype **source, struct cardtype **dest)
624 struct cardtype *temp;
627 *source = (*source)->next;
633 * Procedure to set the cards on the foundation base when available.
634 * Note that it is only called on a foundation pile at the beginning of
635 * the game, so the pile will have exactly one card in it.
638 fndbase(struct cardtype **cp, int column, int row)
644 if ((*cp)->rank == basecard->rank) {
646 printcard(pilemap[base], foundrow, *cp);
647 if (*cp == tableau[0])
648 length[0] = length[0] - 1;
649 if (*cp == tableau[1])
650 length[1] = length[1] - 1;
651 if (*cp == tableau[2])
652 length[2] = length[2] - 1;
653 if (*cp == tableau[3])
654 length[3] = length[3] - 1;
655 transit(cp, &found[base]);
661 printcard(column, row, *cp);
664 removecard(column, row);
669 this.wins += valuepercardup;
670 game.wins += valuepercardup;
671 total.wins += valuepercardup;
675 } while (nomore == FALSE);
679 * procedure to initialize the things necessary for the game
686 for (i=0; i<18; i++) {
687 deck[i]->visible = TRUE;
688 deck[i]->paid = TRUE;
692 for (i=12; i>=1; i--)
693 deck[i]->next = deck[i - 1];
696 deck[13]->next = NIL;
700 for (i=14; i<18; i++) {
701 tableau[i - 14] = deck[i];
704 for (i=0; i<4; i++) {
705 bottom[i] = tableau[i];
709 for (i=18; i<decksize-1; i++)
710 deck[i]->next = deck[i + 1];
711 deck[decksize-1]->next = NIL;
721 cnewcol = cinitcol + cwidthcol;
725 * procedure to print the beginning cards and to start each game
734 this.hand = costofhand;
735 game.hand += costofhand;
736 total.hand += costofhand;
740 this.information = 0;
745 printcard(foundcol, foundrow, found[0]);
746 printcard(stockcol, stockrow, stock);
747 printcard(atabcol, tabrow, tableau[0]);
748 printcard(btabcol, tabrow, tableau[1]);
749 printcard(ctabcol, tabrow, tableau[2]);
750 printcard(dtabcol, tabrow, tableau[3]);
751 printcard(taloncol, talonrow, talon);
752 move(foundrow - 2, basecol);
754 move(foundrow - 1, basecol);
756 printrank(basecol, foundrow, found[0], 0);
758 fndbase(&tableau[j], pilemap[j], tabrow);
759 fndbase(&stock, stockcol, stockrow);
760 showstat(); /* show card counting info to cheaters */
766 * procedure to clear the message printed from an error
773 if (errmsg == TRUE) {
775 move(msgrow, msgcol);
783 * procedure to print an error message if the move is not listed
789 move(msgrow, msgcol);
790 printw("Not a proper move ");
794 * procedure to print an error message if the move is not possible
800 move(msgrow, msgcol);
801 printw("Error: Can't move there");
805 * function to see if the source has cards in it
808 notempty(struct cardtype *cp)
812 move(msgrow, msgcol);
813 printw("Error: no cards to move");
820 * function to see if the rank of one card is less than another
823 ranklower(struct cardtype *cp1, struct cardtype *cp2)
825 if (cp2->rank == Ace)
826 if (cp1->rank == King)
830 else if (cp1->rank + 1 == cp2->rank)
837 * function to check the cardcolor for moving to a tableau
840 diffcolor(struct cardtype *cp1, struct cardtype *cp2)
842 if (cp1->color == cp2->color)
849 * function to see if the card can move to the tableau
852 tabok(struct cardtype *cp, int des)
854 if ((cp == stock) && (tableau[des] == NIL))
856 else if (tableau[des] == NIL)
858 cp != bottom[0] && cp != bottom[1] &&
859 cp != bottom[2] && cp != bottom[3])
863 else if (ranklower(cp, tableau[des]) && diffcolor(cp, tableau[des]))
870 * procedure to turn the cards onto the talon from the deck
877 if (cinhand <= 3 && cinhand > 0) {
878 move(msgrow, msgcol);
879 printw("Hand is now empty ");
883 else if (cinhand > 0)
885 else if (talon != NIL) {
888 move(msgrow, msgcol);
889 if (timesthru != 4) {
890 printw("Talon is now the new hand");
891 this.runs += costofrunthroughhand;
892 game.runs += costofrunthroughhand;
893 total.runs += costofrunthroughhand;
894 while (talon != NIL) {
895 transit(&talon, &hand);
906 cnewcol = cinitcol + cwidthcol;
912 printw("I believe you have lost");
918 move(msgrow, msgcol);
919 printw("Talon and hand are empty");
922 for (i=0; i<fin; i++) {
923 transit(&hand, &talon);
924 INCRHAND(cnewrow, cnewcol);
925 INCRHAND(coldrow, coldcol);
926 removecard(cnewcol, cnewrow);
928 talon->visible = TRUE;
930 if (talon->paid == FALSE && talon->visible == TRUE) {
931 this.information += costofinformation;
932 game.information += costofinformation;
933 total.information += costofinformation;
936 printcard(coldcol, coldrow, talon);
940 printcard(taloncol, talonrow, talon);
944 move(handstatrow, handstatcol);
945 printw("%3d", cinhand);
946 move(talonstatrow, talonstatcol);
947 printw("%3d", taloncnt);
949 fndbase(&talon, taloncol, talonrow);
955 * procedure to print card counting info on screen
961 struct cardtype *ptr;
965 move(talonstatrow, talonstatcol - 7);
966 printw("Talon: %3d", taloncnt);
967 move(handstatrow, handstatcol - 7);
968 printw("Hand: %3d", cinhand);
969 move(stockstatrow, stockstatcol - 7);
970 printw("Stock: %3d", stockcnt);
971 for ( row = coldrow, col = coldcol, ptr = talon;
974 if (ptr->paid == FALSE && ptr->visible == TRUE) {
976 this.information += costofinformation;
977 game.information += costofinformation;
978 total.information += costofinformation;
980 printcard(col, row, ptr);
983 for ( row = cnewrow, col = cnewcol, ptr = hand;
986 if (ptr->paid == FALSE && ptr->visible == TRUE) {
988 this.information += costofinformation;
989 game.information += costofinformation;
990 total.information += costofinformation;
993 printcard(col, row, ptr);
998 * procedure to clear card counting info from screen
1005 move(talonstatrow, talonstatcol - 7);
1007 move(handstatrow, handstatcol - 7);
1009 move(stockstatrow, stockstatcol - 7);
1011 for ( row = ctoprow ; row <= cbotrow ; row++ ) {
1012 move(row, cinitcol);
1013 printw("%56s", " ");
1018 * procedure to update card counting base
1023 removecard(coldcol, coldrow);
1024 DECRHAND(coldrow, coldcol);
1025 if (talon != NIL && (talon->visible == FALSE)) {
1026 talon->visible = TRUE;
1028 this.information += costofinformation;
1029 game.information += costofinformation;
1030 total.information += costofinformation;
1032 printcard(coldcol, coldrow, talon);
1037 move(talonstatrow, talonstatcol);
1038 printw("%3d", taloncnt);
1043 * procedure to update stock card counting base
1050 move(stockstatrow, stockstatcol);
1051 printw("%3d", stockcnt);
1056 * let 'em know how they lost!
1061 struct cardtype *ptr;
1064 if (!Cflag || cardsoff == 52)
1066 for (ptr = talon; ptr != NIL; ptr = ptr->next) {
1067 ptr->visible = TRUE;
1070 for (ptr = hand; ptr != NIL; ptr = ptr->next) {
1071 ptr->visible = TRUE;
1075 move(stockrow + 1, sidecol);
1077 move(talonrow - 2, sidecol);
1079 move(talonrow - 1, sidecol);
1081 move(talonrow, sidecol);
1083 move(talonrow + 1, sidecol);
1085 for (ptr = stock, row = stockrow; ptr != NIL; ptr = ptr->next, row++) {
1086 move(row, stockcol - 1);
1088 printcard(stockcol, row, ptr);
1091 move(row, stockcol - 1);
1095 move(handstatrow, handstatcol - 7);
1097 move(row, stockcol - 1);
1099 if ( cardsoff == 52 )
1100 getcmd(moverow, movecol, "Hit return to exit");
1104 * procedure to update the betting values
1107 updatebettinginfo(void)
1109 long thiscosts, gamecosts, totalcosts;
1110 double thisreturn, gamereturn, totalreturn;
1115 dollars = (now - acctstart) / secondsperdollar;
1117 acctstart += dollars * secondsperdollar;
1118 if (dollars > maxtimecharge)
1119 dollars = maxtimecharge;
1120 this.thinktime += dollars;
1121 game.thinktime += dollars;
1122 total.thinktime += dollars;
1124 thiscosts = this.hand + this.inspection + this.game +
1125 this.runs + this.information + this.thinktime;
1126 gamecosts = game.hand + game.inspection + game.game +
1127 game.runs + game.information + game.thinktime;
1128 totalcosts = total.hand + total.inspection + total.game +
1129 total.runs + total.information + total.thinktime;
1130 this.worth = this.wins - thiscosts;
1131 game.worth = game.wins - gamecosts;
1132 total.worth = total.wins - totalcosts;
1133 thisreturn = ((double)this.wins / (double)thiscosts - 1.0) * 100.0;
1134 gamereturn = ((double)game.wins / (double)gamecosts - 1.0) * 100.0;
1135 totalreturn = ((double)total.wins / (double)totalcosts - 1.0) * 100.0;
1136 if (status != BETTINGBOX)
1138 move(tboxrow + 2, boxcol + 13);
1139 printw("%4d%8d%9d", this.hand, game.hand, total.hand);
1140 move(tboxrow + 3, boxcol + 13);
1141 printw("%4d%8d%9d", this.inspection, game.inspection, total.inspection);
1142 move(tboxrow + 4, boxcol + 13);
1143 printw("%4d%8d%9d", this.game, game.game, total.game);
1144 move(tboxrow + 5, boxcol + 13);
1145 printw("%4d%8d%9d", this.runs, game.runs, total.runs);
1146 move(tboxrow + 6, boxcol + 13);
1147 printw("%4d%8d%9d", this.information, game.information,
1149 move(tboxrow + 7, boxcol + 13);
1150 printw("%4d%8d%9d", this.thinktime, game.thinktime, total.thinktime);
1151 move(tboxrow + 8, boxcol + 13);
1152 printw("%4d%8d%9d", thiscosts, gamecosts, totalcosts);
1153 move(tboxrow + 9, boxcol + 13);
1154 printw("%4d%8d%9d", this.wins, game.wins, total.wins);
1155 move(tboxrow + 10, boxcol + 13);
1156 printw("%4d%8d%9d", this.worth, game.worth, total.worth);
1157 move(tboxrow + 11, boxcol + 13);
1158 printw("%4.0f%%%7.1f%%%8.1f%%", thisreturn, gamereturn, totalreturn);
1162 * procedure to move a card from the stock or talon to the tableau
1165 simpletableau(struct cardtype **cp, int des)
1169 if (notempty(*cp)) {
1170 if (tabok(*cp, des)) {
1175 if (tableau[des] == NIL)
1177 transit(cp, &tableau[des]);
1179 printcard(pilemap[des], length[des], tableau[des]);
1181 if (origin == stk) {
1183 printcard(stockcol, stockrow, stock);
1186 printcard(taloncol, talonrow, talon);
1197 tabprint(int sour, int des)
1199 int dlength, slength, i;
1200 struct cardtype *tempcard;
1202 for (i=tabrow; i<=length[sour]; i++)
1203 removecard(pilemap[sour], i);
1204 dlength = length[des] + 1;
1205 slength = length[sour];
1206 if (slength == tabrow)
1207 printcard(pilemap[des], dlength, tableau[sour]);
1209 while (slength != tabrow - 1) {
1210 tempcard = tableau[sour];
1211 for (i=1; i<=slength-tabrow; i++)
1212 tempcard = tempcard->next;
1213 printcard(pilemap[des], dlength, tempcard);
1220 * procedure to move from the tableau to the tableau
1223 tabtotab(int sour, int des)
1225 struct cardtype *temp;
1227 if (notempty(tableau[sour])) {
1228 if (tabok(bottom[sour], des)) {
1229 tabprint(sour, des);
1230 temp = bottom[sour];
1232 if (bottom[des] == NIL)
1234 temp->next = tableau[des];
1235 tableau[des] = tableau[sour];
1236 tableau[sour] = NIL;
1237 length[des] = length[des] + (length[sour] - (tabrow - 1));
1238 length[sour] = tabrow - 1;
1246 * functions to see if the card can go onto the foundation
1249 rankhigher(struct cardtype *cp, int let)
1251 if (found[let]->rank == King)
1252 if (cp->rank == Ace)
1256 else if (cp->rank - 1 == found[let]->rank)
1263 * function to determine if two cards are the same suit
1266 samesuit(struct cardtype *cp, int let)
1268 if (cp->suit == found[let]->suit)
1275 * procedure to move a card to the correct foundation pile
1278 movetofound(struct cardtype **cp, int source)
1282 if (notempty(*cp)) {
1284 if (found[tempbase] != NIL)
1285 if (rankhigher(*cp, tempbase)
1286 && samesuit(*cp, tempbase)) {
1289 else if (*cp == talon)
1293 transit(cp, &found[tempbase]);
1294 printcard(pilemap[tempbase],
1295 foundrow, found[tempbase]);
1297 if (mtforigin == stk) {
1299 printcard(stockcol, stockrow, stock);
1300 } else if (mtforigin == tal) {
1302 printcard(taloncol, talonrow, talon);
1304 removecard(pilemap[source], length[source]);
1309 this.wins += valuepercardup;
1310 game.wins += valuepercardup;
1311 total.wins += valuepercardup;
1318 } while ((tempbase != 4) && !mtfdone);
1325 * procedure to get a command
1328 getcmd(int row, int col, const char *cp)
1335 printw("%-24s", cp);
1336 col += 1 + strlen(cp);
1340 ch = getch() & 0177;
1341 if (ch >= 'A' && ch <= 'Z')
1346 } else if (i >= 2 && ch != erasechar() && ch != killchar()) {
1347 if (ch != '\n' && ch != '\r' && ch != ' ')
1348 write(1, "\007", 1);
1349 } else if (ch == erasechar() && i > 0) {
1353 } else if (ch == killchar() && i > 0) {
1359 } else if (ch == '\032') { /* Control-Z */
1363 } else if (isprint(ch)) {
1368 } while (ch != '\n' && ch != '\r' && ch != ' ');
1374 * Suspend the game (shell escape if no process control on system)
1383 updatebettinginfo();
1387 lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1388 write(dbfd, (char *)&total, sizeof(total));
1390 kill(getpid(), SIGTSTP);
1396 * procedure to evaluate and make the specific moves
1402 char osrcpile, odestpile;
1409 if (talon == NIL && hand != NIL)
1411 if (cardsoff == 52) {
1414 } else if (!startedgame) {
1415 move(msgrow, msgcol);
1417 switch (34 - taloncnt - cinhand) {
1422 printw("One card used from talon ");
1425 printw("Two cards used from talon ");
1428 printw(">3< cards used from talon ");
1431 getcmd(moverow, movecol, "Move:");
1433 getcmd(moverow, movecol, "Move:");
1435 if (srcpile >= '1' && srcpile <= '4')
1436 source = (int) (srcpile - '1');
1437 if (destpile >= '1' && destpile <= '4')
1438 dest = (int) (destpile - '1');
1440 (srcpile == 't' || srcpile == 's' || srcpile == 'h' ||
1441 srcpile == '1' || srcpile == '2' || srcpile == '3' ||
1445 odestpile = destpile;
1446 if (status != BETTINGBOX)
1449 getcmd(moverow, movecol, "Inspect game?");
1450 } while (srcpile != 'y' && srcpile != 'n');
1451 if (srcpile == 'n') {
1454 this.inspection += costofinspection;
1455 game.inspection += costofinspection;
1456 total.inspection += costofinspection;
1458 destpile = odestpile;
1463 if (destpile == 'f' || destpile == 'F')
1464 movetofound(&talon, source);
1465 else if (destpile >= '1' && destpile <= '4')
1466 simpletableau(&talon, dest);
1471 if (destpile == 'f' || destpile == 'F')
1472 movetofound(&stock, source);
1473 else if (destpile >= '1' && destpile <= '4')
1474 simpletableau(&stock, dest);
1478 if (destpile != 't' && destpile != 'T') {
1486 if (status == BETTINGBOX) {
1488 getcmd(moverow, movecol,
1490 } while (srcpile != 'y' &&
1492 if (srcpile == 'n') {
1499 this.wins += valuepercardup * cardsoff;
1500 game.wins += valuepercardup * cardsoff;
1501 total.wins += valuepercardup * cardsoff;
1502 this.game += costofgame;
1503 game.game += costofgame;
1504 total.game += costofgame;
1512 printtopbettingbox();
1513 printbottombettingbox();
1514 status = BETTINGBOX;
1517 clearabovemovebox();
1518 clearbelowmovebox();
1522 printtopinstructions();
1523 printbottominstructions();
1524 status = INSTRUCTIONBOX;
1533 case '1': case '2': case '3': case '4':
1534 if (destpile == 'f' || destpile == 'F')
1535 movetofound(&tableau[source], source);
1536 else if (destpile >= '1' && destpile <= '4')
1537 tabtotab(source, dest);
1543 fndbase(&stock, stockcol, stockrow);
1544 fndbase(&talon, taloncol, talonrow);
1545 updatebettinginfo();
1549 const char *const basicinstructions[] = {
1550 "Here are brief instuctions to the game of Canfield:\n\n",
1551 " If you have never played solitaire before, it is recom-\n",
1552 "mended that you consult a solitaire instruction book. In\n",
1553 "Canfield, tableau cards may be built on each other downward\n",
1554 "in alternate colors. An entire pile must be moved as a unit\n",
1555 "in building. Top cards of the piles are available to be able\n",
1556 "to be played on foundations, but never into empty spaces.\n\n",
1557 " Spaces must be filled from the stock. The top card of\n",
1558 "the stock also is available to be played on foundations or\n",
1559 "built on tableau piles. After the stock is exhausted, ta-\n",
1560 "bleau spaces may be filled from the talon and the player may\n",
1561 "keep them open until he wishes to use them.\n\n",
1562 " Cards are dealt from the hand to the talon by threes\n",
1563 "and this repeats until there are no more cards in the hand\n",
1564 "or the player quits. To have cards dealt onto the talon the\n",
1565 "player types 'ht' for his move. Foundation base cards are\n",
1566 "also automatically moved to the foundation when they become\n",
1568 "push any key when you are finished: ",
1571 const char *const bettinginstructions[] = {
1572 " The rules for betting are somewhat less strict than\n",
1573 "those used in the official version of the game. The initial\n",
1574 "deal costs $13. You may quit at this point or inspect the\n",
1575 "game. Inspection costs $13 and allows you to make as many\n",
1576 "moves as is possible without moving any cards from your hand\n",
1577 "to the talon. (the initial deal places three cards on the\n",
1578 "talon; if all these cards are used, three more are made\n",
1579 "available) Finally, if the game seems interesting, you must\n",
1580 "pay the final installment of $26. At this point you are\n",
1581 "credited at the rate of $5 for each card on the foundation;\n",
1582 "as the game progresses you are credited with $5 for each\n",
1583 "card that is moved to the foundation. Each run through the\n",
1584 "hand after the first costs $5. The card counting feature\n",
1585 "costs $1 for each unknown card that is identified. If the\n",
1586 "information is toggled on, you are only charged for cards\n",
1587 "that became visible since it was last turned on. Thus the\n",
1588 "maximum cost of information is $34. Playing time is charged\n",
1589 "at a rate of $1 per minute.\n\n",
1590 "push any key when you are finished: ",
1594 * procedure to printout instructions
1599 const char *const *cp;
1601 move(originrow, origincol);
1602 printw("This is the game of solitaire called Canfield. Do\n");
1603 printw("you want instructions for the game?");
1605 getcmd(originrow + 3, origincol, "y or n?");
1606 } while (srcpile != 'y' && srcpile != 'n');
1610 for (cp = basicinstructions; *cp != 0; cp++)
1615 move(originrow, origincol);
1616 printw("Do you want instructions for betting?");
1618 getcmd(originrow + 2, origincol, "y or n?");
1619 } while (srcpile != 'y' && srcpile != 'n');
1623 for (cp = bettinginstructions; *cp != 0; cp++)
1630 * procedure to initialize the game
1644 i = lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1650 i = read(dbfd, (char *)&total, sizeof(total));
1659 * procedure to end the game
1666 if (cardsoff == 52) {
1667 getcmd(moverow, movecol, "Hit return to exit");
1670 move(originrow, origincol);
1671 printw("CONGRATULATIONS!\n");
1672 printw("You won the game. That is a feat to be proud of.\n");
1673 row = originrow + 5;
1676 move(msgrow, msgcol);
1677 printw("You got %d card", cardsoff);
1681 move(msgrow, msgcol);
1686 getcmd(row, col, "Play again (y or n)?");
1687 } while (srcpile != 'y' && srcpile != 'n');
1697 * procedure to clean up and exit
1700 cleanup(__unused int sig)
1703 total.thinktime += 1;
1705 updatebettinginfo();
1707 lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1708 write(dbfd, (char *)&total, sizeof(total));
1720 * Field an interrupt.
1723 askquit(__unused int sig)
1725 move(msgrow, msgcol);
1726 printw("Really wish to quit? ");
1728 getcmd(moverow, movecol, "y or n?");
1729 } while (srcpile != 'y' && srcpile != 'n');
1733 signal(SIGINT, askquit);
1737 * Can you tell that this used to be a Pascal program?
1742 dbfd = open(_PATH_SCORE, O_RDWR);
1751 if (vec[2] >= MAXLOAD) {
1752 puts("The system load is too high. Try again later.");
1756 signal(SIGINT, askquit);
1757 signal(SIGHUP, cleanup);
1758 signal(SIGTERM, cleanup);
1778 return (EXIT_FAILURE);