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>
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;
193 static void askquit(int);
194 static void cleanup(int);
195 static void cleanupboard(void);
196 static void clearabovemovebox(void);
197 static void clearbelowmovebox(void);
198 static void clearmsg(void);
199 static void clearstat(void);
200 static void destinerror(void);
201 static bool diffcolor(struct cardtype *, struct cardtype *);
202 static void dumberror(void);
203 static bool finish(void);
204 static void fndbase(struct cardtype **, int, int);
205 static void getcmd(int, int, const char *);
206 static void initall(void);
207 static void initdeck(struct cardtype **);
208 static void initgame(void);
209 static void instruct(void);
210 static void makeboard(void);
211 static void movebox(void);
212 static void movecard(void);
213 static void movetofound(struct cardtype **, int);
214 static void movetotalon(void);
215 static bool notempty(struct cardtype *);
216 static void printbottombettingbox(void);
217 static void printbottominstructions(void);
218 static void printcard(int, int, struct cardtype *);
219 static void printrank(int, int, struct cardtype *, bool);
220 static void printtopbettingbox(void);
221 static void printtopinstructions(void);
222 static bool rankhigher(struct cardtype *, int);
223 static bool ranklower(struct cardtype *, struct cardtype *);
224 static void removecard(int, int);
225 static bool samesuit(struct cardtype *, int);
226 static void showcards(void);
227 static void showstat(void);
228 static void shuffle(struct cardtype **);
229 static void simpletableau(struct cardtype **, int);
230 static void startgame(void);
231 static void suspend(void);
232 static bool tabok(struct cardtype *, int);
233 static void tabprint(int, int);
234 static void tabtotab(int, int);
235 static void transit(struct cardtype **, struct cardtype **);
236 static void updatebettinginfo(void);
237 static void usedstock(void);
238 static 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(void)
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.
317 printtopbettingbox(void)
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
352 clearabovemovebox(void)
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(void)
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(void)
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
396 clearbelowmovebox(void)
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
508 initdeck(struct cardtype **ldeck)
516 for (scnt=0; scnt<4; scnt++) {
518 for (r=Ace; r<=King; r++) {
519 ldeck[i] = &cards[i];
522 cards[i].color = colormap[scnt];
530 * procedure to shuffle the deck
533 shuffle(struct cardtype **ldeck)
536 struct cardtype *temp;
538 for (i=0; i<decksize; i++) {
539 ldeck[i]->visible = FALSE;
540 ldeck[i]->paid = FALSE;
542 for (i = decksize-1; i>=0; i--) {
543 j = random() % decksize;
553 * procedure to remove the card from the board
556 removecard(int a, int b)
563 * procedure to print the cards on the board
566 printrank(int a, int b, struct cardtype *cp, bool inverse)
574 case 2: case 3: case 4: case 5: case 6: case 7:
575 case 8: case 9: case 10:
576 printw("%d", cp->rank);
595 * procedure to print out a card
598 printcard(int a, int b, struct cardtype *cp)
602 else if (cp->visible == FALSE) {
606 bool inverse = (cp->suit == 'd' || cp->suit == 'h');
608 printrank(a, b, cp, inverse);
618 * procedure to move the top card from one location to the top
619 * of another location. The pointers always point to the top
623 transit(struct cardtype **source, struct cardtype **dest)
625 struct cardtype *temp;
628 *source = (*source)->next;
634 * Procedure to set the cards on the foundation base when available.
635 * Note that it is only called on a foundation pile at the beginning of
636 * the game, so the pile will have exactly one card in it.
639 fndbase(struct cardtype **cp, int column, int row)
645 if ((*cp)->rank == basecard->rank) {
647 printcard(pilemap[base], foundrow, *cp);
648 if (*cp == tableau[0])
649 length[0] = length[0] - 1;
650 if (*cp == tableau[1])
651 length[1] = length[1] - 1;
652 if (*cp == tableau[2])
653 length[2] = length[2] - 1;
654 if (*cp == tableau[3])
655 length[3] = length[3] - 1;
656 transit(cp, &found[base]);
662 printcard(column, row, *cp);
665 removecard(column, row);
670 this.wins += valuepercardup;
671 game.wins += valuepercardup;
672 total.wins += valuepercardup;
676 } while (nomore == FALSE);
680 * procedure to initialize the things necessary for the game
687 for (i=0; i<18; i++) {
688 deck[i]->visible = TRUE;
689 deck[i]->paid = TRUE;
693 for (i=12; i>=1; i--)
694 deck[i]->next = deck[i - 1];
697 deck[13]->next = NIL;
701 for (i=14; i<18; i++) {
702 tableau[i - 14] = deck[i];
705 for (i=0; i<4; i++) {
706 bottom[i] = tableau[i];
710 for (i=18; i<decksize-1; i++)
711 deck[i]->next = deck[i + 1];
712 deck[decksize-1]->next = NIL;
722 cnewcol = cinitcol + cwidthcol;
726 * procedure to print the beginning cards and to start each game
735 this.hand = costofhand;
736 game.hand += costofhand;
737 total.hand += costofhand;
741 this.information = 0;
746 printcard(foundcol, foundrow, found[0]);
747 printcard(stockcol, stockrow, stock);
748 printcard(atabcol, tabrow, tableau[0]);
749 printcard(btabcol, tabrow, tableau[1]);
750 printcard(ctabcol, tabrow, tableau[2]);
751 printcard(dtabcol, tabrow, tableau[3]);
752 printcard(taloncol, talonrow, talon);
753 move(foundrow - 2, basecol);
755 move(foundrow - 1, basecol);
757 printrank(basecol, foundrow, found[0], 0);
759 fndbase(&tableau[j], pilemap[j], tabrow);
760 fndbase(&stock, stockcol, stockrow);
761 showstat(); /* show card counting info to cheaters */
767 * procedure to clear the message printed from an error
774 if (errmsg == TRUE) {
776 move(msgrow, msgcol);
784 * procedure to print an error message if the move is not listed
790 move(msgrow, msgcol);
791 printw("Not a proper move ");
795 * procedure to print an error message if the move is not possible
801 move(msgrow, msgcol);
802 printw("Error: Can't move there");
806 * function to see if the source has cards in it
809 notempty(struct cardtype *cp)
813 move(msgrow, msgcol);
814 printw("Error: no cards to move");
821 * function to see if the rank of one card is less than another
824 ranklower(struct cardtype *cp1, struct cardtype *cp2)
826 if (cp2->rank == Ace)
827 if (cp1->rank == King)
831 else if (cp1->rank + 1 == cp2->rank)
838 * function to check the cardcolor for moving to a tableau
841 diffcolor(struct cardtype *cp1, struct cardtype *cp2)
843 if (cp1->color == cp2->color)
850 * function to see if the card can move to the tableau
853 tabok(struct cardtype *cp, int des)
855 if ((cp == stock) && (tableau[des] == NIL))
857 else if (tableau[des] == NIL)
859 cp != bottom[0] && cp != bottom[1] &&
860 cp != bottom[2] && cp != bottom[3])
864 else if (ranklower(cp, tableau[des]) && diffcolor(cp, tableau[des]))
871 * procedure to turn the cards onto the talon from the deck
878 if (cinhand <= 3 && cinhand > 0) {
879 move(msgrow, msgcol);
880 printw("Hand is now empty ");
884 else if (cinhand > 0)
886 else if (talon != NIL) {
889 move(msgrow, msgcol);
890 if (timesthru != 4) {
891 printw("Talon is now the new hand");
892 this.runs += costofrunthroughhand;
893 game.runs += costofrunthroughhand;
894 total.runs += costofrunthroughhand;
895 while (talon != NIL) {
896 transit(&talon, &hand);
907 cnewcol = cinitcol + cwidthcol;
913 printw("I believe you have lost");
919 move(msgrow, msgcol);
920 printw("Talon and hand are empty");
923 for (i=0; i<fin; i++) {
924 transit(&hand, &talon);
925 INCRHAND(cnewrow, cnewcol);
926 INCRHAND(coldrow, coldcol);
927 removecard(cnewcol, cnewrow);
929 talon->visible = TRUE;
931 if (talon->paid == FALSE && talon->visible == TRUE) {
932 this.information += costofinformation;
933 game.information += costofinformation;
934 total.information += costofinformation;
937 printcard(coldcol, coldrow, talon);
941 printcard(taloncol, talonrow, talon);
945 move(handstatrow, handstatcol);
946 printw("%3d", cinhand);
947 move(talonstatrow, talonstatcol);
948 printw("%3d", taloncnt);
950 fndbase(&talon, taloncol, talonrow);
956 * procedure to print card counting info on screen
962 struct cardtype *ptr;
966 move(talonstatrow, talonstatcol - 7);
967 printw("Talon: %3d", taloncnt);
968 move(handstatrow, handstatcol - 7);
969 printw("Hand: %3d", cinhand);
970 move(stockstatrow, stockstatcol - 7);
971 printw("Stock: %3d", stockcnt);
972 for ( row = coldrow, col = coldcol, ptr = talon;
975 if (ptr->paid == FALSE && ptr->visible == TRUE) {
977 this.information += costofinformation;
978 game.information += costofinformation;
979 total.information += costofinformation;
981 printcard(col, row, ptr);
984 for ( row = cnewrow, col = cnewcol, ptr = hand;
987 if (ptr->paid == FALSE && ptr->visible == TRUE) {
989 this.information += costofinformation;
990 game.information += costofinformation;
991 total.information += costofinformation;
994 printcard(col, row, ptr);
999 * procedure to clear card counting info from screen
1006 move(talonstatrow, talonstatcol - 7);
1008 move(handstatrow, handstatcol - 7);
1010 move(stockstatrow, stockstatcol - 7);
1012 for ( row = ctoprow ; row <= cbotrow ; row++ ) {
1013 move(row, cinitcol);
1014 printw("%56s", " ");
1019 * procedure to update card counting base
1024 removecard(coldcol, coldrow);
1025 DECRHAND(coldrow, coldcol);
1026 if (talon != NIL && (talon->visible == FALSE)) {
1027 talon->visible = TRUE;
1029 this.information += costofinformation;
1030 game.information += costofinformation;
1031 total.information += costofinformation;
1033 printcard(coldcol, coldrow, talon);
1038 move(talonstatrow, talonstatcol);
1039 printw("%3d", taloncnt);
1044 * procedure to update stock card counting base
1051 move(stockstatrow, stockstatcol);
1052 printw("%3d", stockcnt);
1057 * let 'em know how they lost!
1062 struct cardtype *ptr;
1065 if (!Cflag || cardsoff == 52)
1067 for (ptr = talon; ptr != NIL; ptr = ptr->next) {
1068 ptr->visible = TRUE;
1071 for (ptr = hand; ptr != NIL; ptr = ptr->next) {
1072 ptr->visible = TRUE;
1076 move(stockrow + 1, sidecol);
1078 move(talonrow - 2, sidecol);
1080 move(talonrow - 1, sidecol);
1082 move(talonrow, sidecol);
1084 move(talonrow + 1, sidecol);
1086 for (ptr = stock, row = stockrow; ptr != NIL; ptr = ptr->next, row++) {
1087 move(row, stockcol - 1);
1089 printcard(stockcol, row, ptr);
1092 move(row, stockcol - 1);
1096 move(handstatrow, handstatcol - 7);
1098 move(row, stockcol - 1);
1100 if ( cardsoff == 52 )
1101 getcmd(moverow, movecol, "Hit return to exit");
1105 * procedure to update the betting values
1108 updatebettinginfo(void)
1110 long thiscosts, gamecosts, totalcosts;
1111 double thisreturn, gamereturn, totalreturn;
1116 dollars = (now - acctstart) / secondsperdollar;
1118 acctstart += dollars * secondsperdollar;
1119 if (dollars > maxtimecharge)
1120 dollars = maxtimecharge;
1121 this.thinktime += dollars;
1122 game.thinktime += dollars;
1123 total.thinktime += dollars;
1125 thiscosts = this.hand + this.inspection + this.game +
1126 this.runs + this.information + this.thinktime;
1127 gamecosts = game.hand + game.inspection + game.game +
1128 game.runs + game.information + game.thinktime;
1129 totalcosts = total.hand + total.inspection + total.game +
1130 total.runs + total.information + total.thinktime;
1131 this.worth = this.wins - thiscosts;
1132 game.worth = game.wins - gamecosts;
1133 total.worth = total.wins - totalcosts;
1134 thisreturn = ((double)this.wins / (double)thiscosts - 1.0) * 100.0;
1135 gamereturn = ((double)game.wins / (double)gamecosts - 1.0) * 100.0;
1136 totalreturn = ((double)total.wins / (double)totalcosts - 1.0) * 100.0;
1137 if (status != BETTINGBOX)
1139 move(tboxrow + 2, boxcol + 13);
1140 printw("%4d%8d%9d", this.hand, game.hand, total.hand);
1141 move(tboxrow + 3, boxcol + 13);
1142 printw("%4d%8d%9d", this.inspection, game.inspection, total.inspection);
1143 move(tboxrow + 4, boxcol + 13);
1144 printw("%4d%8d%9d", this.game, game.game, total.game);
1145 move(tboxrow + 5, boxcol + 13);
1146 printw("%4d%8d%9d", this.runs, game.runs, total.runs);
1147 move(tboxrow + 6, boxcol + 13);
1148 printw("%4d%8d%9d", this.information, game.information,
1150 move(tboxrow + 7, boxcol + 13);
1151 printw("%4d%8d%9d", this.thinktime, game.thinktime, total.thinktime);
1152 move(tboxrow + 8, boxcol + 13);
1153 printw("%4d%8d%9d", thiscosts, gamecosts, totalcosts);
1154 move(tboxrow + 9, boxcol + 13);
1155 printw("%4d%8d%9d", this.wins, game.wins, total.wins);
1156 move(tboxrow + 10, boxcol + 13);
1157 printw("%4d%8d%9d", this.worth, game.worth, total.worth);
1158 move(tboxrow + 11, boxcol + 13);
1159 printw("%4.0f%%%7.1f%%%8.1f%%", thisreturn, gamereturn, totalreturn);
1163 * procedure to move a card from the stock or talon to the tableau
1166 simpletableau(struct cardtype **cp, int des)
1170 if (notempty(*cp)) {
1171 if (tabok(*cp, des)) {
1176 if (tableau[des] == NIL)
1178 transit(cp, &tableau[des]);
1180 printcard(pilemap[des], length[des], tableau[des]);
1182 if (origin == stk) {
1184 printcard(stockcol, stockrow, stock);
1187 printcard(taloncol, talonrow, talon);
1198 tabprint(int sour, int des)
1200 int dlength, slength, i;
1201 struct cardtype *tempcard;
1203 for (i=tabrow; i<=length[sour]; i++)
1204 removecard(pilemap[sour], i);
1205 dlength = length[des] + 1;
1206 slength = length[sour];
1207 if (slength == tabrow)
1208 printcard(pilemap[des], dlength, tableau[sour]);
1210 while (slength != tabrow - 1) {
1211 tempcard = tableau[sour];
1212 for (i=1; i<=slength-tabrow; i++)
1213 tempcard = tempcard->next;
1214 printcard(pilemap[des], dlength, tempcard);
1221 * procedure to move from the tableau to the tableau
1224 tabtotab(int sour, int des)
1226 struct cardtype *temp;
1228 if (notempty(tableau[sour])) {
1229 if (tabok(bottom[sour], des)) {
1230 tabprint(sour, des);
1231 temp = bottom[sour];
1233 if (bottom[des] == NIL)
1235 temp->next = tableau[des];
1236 tableau[des] = tableau[sour];
1237 tableau[sour] = NIL;
1238 length[des] = length[des] + (length[sour] - (tabrow - 1));
1239 length[sour] = tabrow - 1;
1247 * functions to see if the card can go onto the foundation
1250 rankhigher(struct cardtype *cp, int let)
1252 if (found[let]->rank == King)
1253 if (cp->rank == Ace)
1257 else if (cp->rank - 1 == found[let]->rank)
1264 * function to determine if two cards are the same suit
1267 samesuit(struct cardtype *cp, int let)
1269 if (cp->suit == found[let]->suit)
1276 * procedure to move a card to the correct foundation pile
1279 movetofound(struct cardtype **cp, int source)
1283 if (notempty(*cp)) {
1285 if (found[tempbase] != NIL)
1286 if (rankhigher(*cp, tempbase)
1287 && samesuit(*cp, tempbase)) {
1290 else if (*cp == talon)
1294 transit(cp, &found[tempbase]);
1295 printcard(pilemap[tempbase],
1296 foundrow, found[tempbase]);
1298 if (mtforigin == stk) {
1300 printcard(stockcol, stockrow, stock);
1301 } else if (mtforigin == tal) {
1303 printcard(taloncol, talonrow, talon);
1305 removecard(pilemap[source], length[source]);
1310 this.wins += valuepercardup;
1311 game.wins += valuepercardup;
1312 total.wins += valuepercardup;
1319 } while ((tempbase != 4) && !mtfdone);
1326 * procedure to get a command
1329 getcmd(int row, int col, const char *cp)
1336 printw("%-24s", cp);
1337 col += 1 + strlen(cp);
1341 ch = getch() & 0177;
1342 if (ch >= 'A' && ch <= 'Z')
1347 } else if (i >= 2 && ch != erasechar() && ch != killchar()) {
1348 if (ch != '\n' && ch != '\r' && ch != ' ')
1349 write(1, "\007", 1);
1350 } else if (ch == erasechar() && i > 0) {
1354 } else if (ch == killchar() && i > 0) {
1360 } else if (ch == '\032') { /* Control-Z */
1364 } else if (isprint(ch)) {
1369 } while (ch != '\n' && ch != '\r' && ch != ' ');
1375 * Suspend the game (shell escape if no process control on system)
1384 updatebettinginfo();
1388 lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1389 write(dbfd, (char *)&total, sizeof(total));
1391 kill(getpid(), SIGTSTP);
1397 * procedure to evaluate and make the specific moves
1403 char osrcpile, odestpile;
1410 if (talon == NIL && hand != NIL)
1412 if (cardsoff == 52) {
1415 } else if (!startedgame) {
1416 move(msgrow, msgcol);
1418 switch (34 - taloncnt - cinhand) {
1423 printw("One card used from talon ");
1426 printw("Two cards used from talon ");
1429 printw(">3< cards used from talon ");
1432 getcmd(moverow, movecol, "Move:");
1434 getcmd(moverow, movecol, "Move:");
1436 if (srcpile >= '1' && srcpile <= '4')
1437 source = (int) (srcpile - '1');
1438 if (destpile >= '1' && destpile <= '4')
1439 dest = (int) (destpile - '1');
1441 (srcpile == 't' || srcpile == 's' || srcpile == 'h' ||
1442 srcpile == '1' || srcpile == '2' || srcpile == '3' ||
1446 odestpile = destpile;
1447 if (status != BETTINGBOX)
1450 getcmd(moverow, movecol, "Inspect game?");
1451 } while (srcpile != 'y' && srcpile != 'n');
1452 if (srcpile == 'n') {
1455 this.inspection += costofinspection;
1456 game.inspection += costofinspection;
1457 total.inspection += costofinspection;
1459 destpile = odestpile;
1464 if (destpile == 'f' || destpile == 'F')
1465 movetofound(&talon, source);
1466 else if (destpile >= '1' && destpile <= '4')
1467 simpletableau(&talon, dest);
1472 if (destpile == 'f' || destpile == 'F')
1473 movetofound(&stock, source);
1474 else if (destpile >= '1' && destpile <= '4')
1475 simpletableau(&stock, dest);
1479 if (destpile != 't' && destpile != 'T') {
1487 if (status == BETTINGBOX) {
1489 getcmd(moverow, movecol,
1491 } while (srcpile != 'y' &&
1493 if (srcpile == 'n') {
1500 this.wins += valuepercardup * cardsoff;
1501 game.wins += valuepercardup * cardsoff;
1502 total.wins += valuepercardup * cardsoff;
1503 this.game += costofgame;
1504 game.game += costofgame;
1505 total.game += costofgame;
1513 printtopbettingbox();
1514 printbottombettingbox();
1515 status = BETTINGBOX;
1518 clearabovemovebox();
1519 clearbelowmovebox();
1523 printtopinstructions();
1524 printbottominstructions();
1525 status = INSTRUCTIONBOX;
1534 case '1': case '2': case '3': case '4':
1535 if (destpile == 'f' || destpile == 'F')
1536 movetofound(&tableau[source], source);
1537 else if (destpile >= '1' && destpile <= '4')
1538 tabtotab(source, dest);
1544 fndbase(&stock, stockcol, stockrow);
1545 fndbase(&talon, taloncol, talonrow);
1546 updatebettinginfo();
1550 const char *const basicinstructions[] = {
1551 "Here are brief instuctions to the game of Canfield:\n\n",
1552 " If you have never played solitaire before, it is recom-\n",
1553 "mended that you consult a solitaire instruction book. In\n",
1554 "Canfield, tableau cards may be built on each other downward\n",
1555 "in alternate colors. An entire pile must be moved as a unit\n",
1556 "in building. Top cards of the piles are available to be able\n",
1557 "to be played on foundations, but never into empty spaces.\n\n",
1558 " Spaces must be filled from the stock. The top card of\n",
1559 "the stock also is available to be played on foundations or\n",
1560 "built on tableau piles. After the stock is exhausted, ta-\n",
1561 "bleau spaces may be filled from the talon and the player may\n",
1562 "keep them open until he wishes to use them.\n\n",
1563 " Cards are dealt from the hand to the talon by threes\n",
1564 "and this repeats until there are no more cards in the hand\n",
1565 "or the player quits. To have cards dealt onto the talon the\n",
1566 "player types 'ht' for his move. Foundation base cards are\n",
1567 "also automatically moved to the foundation when they become\n",
1569 "push any key when you are finished: ",
1572 const char *const bettinginstructions[] = {
1573 " The rules for betting are somewhat less strict than\n",
1574 "those used in the official version of the game. The initial\n",
1575 "deal costs $13. You may quit at this point or inspect the\n",
1576 "game. Inspection costs $13 and allows you to make as many\n",
1577 "moves as is possible without moving any cards from your hand\n",
1578 "to the talon. (the initial deal places three cards on the\n",
1579 "talon; if all these cards are used, three more are made\n",
1580 "available) Finally, if the game seems interesting, you must\n",
1581 "pay the final installment of $26. At this point you are\n",
1582 "credited at the rate of $5 for each card on the foundation;\n",
1583 "as the game progresses you are credited with $5 for each\n",
1584 "card that is moved to the foundation. Each run through the\n",
1585 "hand after the first costs $5. The card counting feature\n",
1586 "costs $1 for each unknown card that is identified. If the\n",
1587 "information is toggled on, you are only charged for cards\n",
1588 "that became visible since it was last turned on. Thus the\n",
1589 "maximum cost of information is $34. Playing time is charged\n",
1590 "at a rate of $1 per minute.\n\n",
1591 "push any key when you are finished: ",
1595 * procedure to printout instructions
1600 const char *const *cp;
1602 move(originrow, origincol);
1603 printw("This is the game of solitaire called Canfield. Do\n");
1604 printw("you want instructions for the game?");
1606 getcmd(originrow + 3, origincol, "y or n?");
1607 } while (srcpile != 'y' && srcpile != 'n');
1611 for (cp = basicinstructions; *cp != 0; cp++)
1616 move(originrow, origincol);
1617 printw("Do you want instructions for betting?");
1619 getcmd(originrow + 2, origincol, "y or n?");
1620 } while (srcpile != 'y' && srcpile != 'n');
1624 for (cp = bettinginstructions; *cp != 0; cp++)
1631 * procedure to initialize the game
1645 i = lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1651 i = read(dbfd, (char *)&total, sizeof(total));
1660 * procedure to end the game
1667 if (cardsoff == 52) {
1668 getcmd(moverow, movecol, "Hit return to exit");
1671 move(originrow, origincol);
1672 printw("CONGRATULATIONS!\n");
1673 printw("You won the game. That is a feat to be proud of.\n");
1674 row = originrow + 5;
1677 move(msgrow, msgcol);
1678 printw("You got %d card", cardsoff);
1682 move(msgrow, msgcol);
1687 getcmd(row, col, "Play again (y or n)?");
1688 } while (srcpile != 'y' && srcpile != 'n');
1698 * procedure to clean up and exit
1701 cleanup(__unused int sig)
1704 total.thinktime += 1;
1706 updatebettinginfo();
1708 lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1709 write(dbfd, (char *)&total, sizeof(total));
1721 * Field an interrupt.
1724 askquit(__unused int sig)
1726 move(msgrow, msgcol);
1727 printw("Really wish to quit? ");
1729 getcmd(moverow, movecol, "y or n?");
1730 } while (srcpile != 'y' && srcpile != 'n');
1734 signal(SIGINT, askquit);
1738 * Can you tell that this used to be a Pascal program?
1743 dbfd = open(_PATH_SCORE, O_RDWR);
1752 if (vec[2] >= MAXLOAD) {
1753 puts("The system load is too high. Try again later.");
1757 signal(SIGINT, askquit);
1758 signal(SIGHUP, cleanup);
1759 signal(SIGTERM, cleanup);
1779 return (EXIT_FAILURE);