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 char copyright[] =
36 "@(#) Copyright (c) 1980, 1993\n\
37 The Regents of the University of California. All rights reserved.\n";
41 static char sccsid[] = "@(#)canfield.c 8.1 (Berkeley) 5/31/93";
45 * The canfield program
48 * Originally written: Steve Levine
49 * Converted to use curses and debugged: Steve Feldman
50 * Card counting: Kirk McKusick and Mikey Olson
51 * User interface cleanups: Eric Allman and Kirk McKusick
52 * Betting by Kirk McKusick
55 #include <sys/types.h>
66 #include "pathnames.h"
97 #define handstatrow 21
99 #define talonstatrow 22
100 #define talonstatcol 7
101 #define stockstatrow 23
102 #define stockstatcol 7
122 #define INCRHAND(row, col) {\
124 if (row < ctoprow) {\
129 #define DECRHAND(row, col) {\
131 if (row > cbotrow) {\
144 struct cardtype *next;
147 #define NIL ((struct cardtype *) -1)
149 struct cardtype *deck[decksize];
150 struct cardtype cards[decksize];
151 struct cardtype *bottom[4], *found[4], *tableau[4];
152 struct cardtype *talon, *hand, *stock, *basecard;
154 int cardsoff, base, cinhand, taloncnt, stockcnt, timesthru;
155 char suitmap[4] = {spades, clubs, hearts, diamonds};
156 char colormap[4] = {black, black, red, red};
157 char pilemap[4] = {atabcol, btabcol, ctabcol, dtabcol};
158 char srcpile, destpile;
159 int mtforigin, tempbase;
160 int coldcol, cnewcol, coldrow, cnewrow;
162 bool mtfdone, Cflag = FALSE;
163 #define INSTRUCTIONBOX 1
166 int status = INSTRUCTIONBOX;
170 * Basic betting costs
172 #define costofhand 13
173 #define costofinspection 13
174 #define costofgame 26
175 #define costofrunthroughhand 5
176 #define costofinformation 1
177 #define secondsperdollar 60
178 #define maxtimecharge 3
179 #define valuepercardup 5
181 * Variables associated with betting
184 long hand; /* cost of dealing hand */
185 long inspection; /* cost of inspecting hand */
186 long game; /* cost of buying game */
187 long runs; /* cost of running through hands */
188 long information; /* cost of information */
189 long thinktime; /* cost of thinking time */
190 long wins; /* total winnings */
191 long worth; /* net worth after costs */
193 struct betinfo this, game, total;
194 bool startedgame = FALSE, infullgame = FALSE;
199 * The following procedures print the board onto the screen using the
200 * addressible cursor. The end of these procedures will also be
201 * separated from the rest of the program.
203 * procedure to set the move command box
209 printtopbettingbox();
215 printtopinstructions();
218 move(moverow, boxcol);
220 move(msgrow, boxcol);
224 printbottombettingbox();
230 printbottominstructions();
237 * print directions above move box
239 printtopinstructions()
241 move(tboxrow, boxcol);
242 printw("*----------------------------------*");
243 move(tboxrow + 1, boxcol);
245 move(tboxrow + 2, boxcol);
246 printw("|s# = stock to tableau |");
247 move(tboxrow + 3, boxcol);
248 printw("|sf = stock to foundation |");
249 move(tboxrow + 4, boxcol);
250 printw("|t# = talon to tableau |");
251 move(tboxrow + 5, boxcol);
252 printw("|tf = talon to foundation |");
253 move(tboxrow + 6, boxcol);
254 printw("|## = tableau to tableau |");
255 move(tboxrow + 7, boxcol);
256 printw("|#f = tableau to foundation |");
257 move(tboxrow + 8, boxcol);
258 printw("|ht = hand to talon |");
259 move(tboxrow + 9, boxcol);
260 printw("|c = toggle card counting |");
261 move(tboxrow + 10, boxcol);
262 printw("|b = present betting information |");
263 move(tboxrow + 11, boxcol);
264 printw("|q = quit to end the game |");
265 move(tboxrow + 12, boxcol);
266 printw("|==================================|");
270 * Print the betting box.
275 move(tboxrow, boxcol);
276 printw("*----------------------------------*");
277 move(tboxrow + 1, boxcol);
278 printw("|Costs Hand Game Total |");
279 move(tboxrow + 2, boxcol);
281 move(tboxrow + 3, boxcol);
282 printw("| Inspections |");
283 move(tboxrow + 4, boxcol);
285 move(tboxrow + 5, boxcol);
287 move(tboxrow + 6, boxcol);
288 printw("| Information |");
289 move(tboxrow + 7, boxcol);
290 printw("| Think time |");
291 move(tboxrow + 8, boxcol);
292 printw("|Total Costs |");
293 move(tboxrow + 9, boxcol);
294 printw("|Winnings |");
295 move(tboxrow + 10, boxcol);
296 printw("|Net Worth |");
297 move(tboxrow + 11, boxcol);
299 move(tboxrow + 12, boxcol);
300 printw("|==================================|");
304 * clear info above move box
310 for (i = 0; i <= 11; i++) {
311 move(tboxrow + i, boxcol);
314 move(tboxrow + 12, boxcol);
315 printw("*----------------------------------*");
319 * print instructions below move box
321 printbottominstructions()
323 move(bboxrow, boxcol);
324 printw("|Replace # with the number of the |");
325 move(bboxrow + 1, boxcol);
326 printw("|tableau you want. |");
327 move(bboxrow + 2, boxcol);
328 printw("*----------------------------------*");
332 * print betting information below move box
334 printbottombettingbox()
336 move(bboxrow, boxcol);
337 printw("|x = toggle information box |");
338 move(bboxrow + 1, boxcol);
339 printw("|i = list playing instructions |");
340 move(bboxrow + 2, boxcol);
341 printw("*----------------------------------*");
345 * clear info below move box
351 move(bboxrow, boxcol);
352 printw("*----------------------------------*");
353 for (i = 1; i <= 2; i++) {
354 move(bboxrow + i, boxcol);
360 * procedure to put the board on the screen using addressable cursor
366 move(titlerow, titlecol);
367 printw("=-> CANFIELD <-=");
368 move(fttlrow, fttlcol);
369 printw("foundation");
370 move(foundrow - 1, fttlcol);
371 printw("=---= =---= =---= =---=");
372 move(foundrow, fttlcol);
373 printw("| | | | | | | |");
374 move(foundrow + 1, fttlcol);
375 printw("=---= =---= =---= =---=");
376 move(ottlrow, sidecol);
377 printw("stock tableau");
378 move(stockrow - 1, sidecol);
380 move(stockrow, sidecol);
382 move(stockrow + 1, sidecol);
384 move(talonrow - 2, sidecol);
386 move(talonrow - 1, sidecol);
388 move(talonrow, sidecol);
390 move(talonrow + 1, sidecol);
392 move(tabrow - 1, atabcol);
393 printw("-1- -2- -3- -4-");
398 * clean up the board for another game
403 struct cardtype *ptr;
407 for(ptr = stock, row = stockrow;
409 ptr = ptr->next, row++) {
415 move(stockrow + 1, sidecol);
417 move(talonrow - 2, sidecol);
419 move(talonrow - 1, sidecol);
421 move(talonrow + 1, sidecol);
424 move(stockrow, sidecol);
426 move(talonrow, sidecol);
428 move(foundrow, fttlcol);
429 printw("| | | | | | | |");
430 for (cnt = 0; cnt < 4; cnt++) {
445 for(ptr = tableau[cnt], row = tabrow;
447 ptr = ptr->next, row++)
448 removecard(col, row);
453 * procedure to create a deck of cards
456 struct cardtype *deck[];
464 for (scnt=0; scnt<4; scnt++) {
466 for (r=Ace; r<=King; r++) {
470 cards[i].color = colormap[scnt];
478 * procedure to shuffle the deck
481 struct cardtype *deck[];
484 struct cardtype *temp;
486 for (i=0; i<decksize; i++) {
487 deck[i]->visible = FALSE;
488 deck[i]->paid = FALSE;
490 for (i = decksize-1; i>=0; i--) {
491 j = random() % decksize;
501 * procedure to remove the card from the board
510 * procedure to print the cards on the board
512 printrank(a, b, cp, inverse)
522 case 2: case 3: case 4: case 5: case 6: case 7:
523 case 8: case 9: case 10:
524 printw("%d", cp->rank);
543 * procedure to print out a card
551 else if (cp->visible == FALSE) {
555 bool inverse = (cp->suit == 'd' || cp->suit == 'h');
557 printrank(a, b, cp, inverse);
567 * procedure to move the top card from one location to the top
568 * of another location. The pointers always point to the top
571 transit(source, dest)
572 struct cardtype **source, **dest;
574 struct cardtype *temp;
577 *source = (*source)->next;
583 * Procedure to set the cards on the foundation base when available.
584 * Note that it is only called on a foundation pile at the beginning of
585 * the game, so the pile will have exactly one card in it.
587 fndbase(cp, column, row)
588 struct cardtype **cp;
594 if ((*cp)->rank == basecard->rank) {
596 printcard(pilemap[base], foundrow, *cp);
597 if (*cp == tableau[0])
598 length[0] = length[0] - 1;
599 if (*cp == tableau[1])
600 length[1] = length[1] - 1;
601 if (*cp == tableau[2])
602 length[2] = length[2] - 1;
603 if (*cp == tableau[3])
604 length[3] = length[3] - 1;
605 transit(cp, &found[base]);
611 printcard(column, row, *cp);
614 removecard(column, row);
619 this.wins += valuepercardup;
620 game.wins += valuepercardup;
621 total.wins += valuepercardup;
625 } while (nomore == FALSE);
629 * procedure to initialize the things necessary for the game
635 for (i=0; i<18; i++) {
636 deck[i]->visible = TRUE;
637 deck[i]->paid = TRUE;
641 for (i=12; i>=1; i--)
642 deck[i]->next = deck[i - 1];
645 deck[13]->next = NIL;
649 for (i=14; i<18; i++) {
650 tableau[i - 14] = deck[i];
653 for (i=0; i<4; i++) {
654 bottom[i] = tableau[i];
658 for (i=18; i<decksize-1; i++)
659 deck[i]->next = deck[i + 1];
660 deck[decksize-1]->next = NIL;
670 cnewcol = cinitcol + cwidthcol;
674 * procedure to print the beginning cards and to start each game
682 this.hand = costofhand;
683 game.hand += costofhand;
684 total.hand += costofhand;
688 this.information = 0;
693 printcard(foundcol, foundrow, found[0]);
694 printcard(stockcol, stockrow, stock);
695 printcard(atabcol, tabrow, tableau[0]);
696 printcard(btabcol, tabrow, tableau[1]);
697 printcard(ctabcol, tabrow, tableau[2]);
698 printcard(dtabcol, tabrow, tableau[3]);
699 printcard(taloncol, talonrow, talon);
700 move(foundrow - 2, basecol);
702 move(foundrow - 1, basecol);
704 printrank(basecol, foundrow, found[0], 0);
706 fndbase(&tableau[j], pilemap[j], tabrow);
707 fndbase(&stock, stockcol, stockrow);
708 showstat(); /* show card counting info to cheaters */
714 * procedure to clear the message printed from an error
720 if (errmsg == TRUE) {
722 move(msgrow, msgcol);
730 * procedure to print an error message if the move is not listed
735 move(msgrow, msgcol);
736 printw("Not a proper move ");
740 * procedure to print an error message if the move is not possible
745 move(msgrow, msgcol);
746 printw("Error: Can't move there");
750 * function to see if the source has cards in it
758 move(msgrow, msgcol);
759 printw("Error: no cards to move");
766 * function to see if the rank of one card is less than another
770 struct cardtype *cp1, *cp2;
772 if (cp2->rank == Ace)
773 if (cp1->rank == King)
777 else if (cp1->rank + 1 == cp2->rank)
784 * function to check the cardcolor for moving to a tableau
788 struct cardtype *cp1, *cp2;
790 if (cp1->color == cp2->color)
797 * function to see if the card can move to the tableau
803 if ((cp == stock) && (tableau[des] == NIL))
805 else if (tableau[des] == NIL)
807 cp != bottom[0] && cp != bottom[1] &&
808 cp != bottom[2] && cp != bottom[3])
812 else if (ranklower(cp, tableau[des]) && diffcolor(cp, tableau[des]))
819 * procedure to turn the cards onto the talon from the deck
825 if (cinhand <= 3 && cinhand > 0) {
826 move(msgrow, msgcol);
827 printw("Hand is now empty ");
831 else if (cinhand > 0)
833 else if (talon != NIL) {
836 move(msgrow, msgcol);
837 if (timesthru != 4) {
838 printw("Talon is now the new hand");
839 this.runs += costofrunthroughhand;
840 game.runs += costofrunthroughhand;
841 total.runs += costofrunthroughhand;
842 while (talon != NIL) {
843 transit(&talon, &hand);
854 cnewcol = cinitcol + cwidthcol;
860 printw("I believe you have lost");
866 move(msgrow, msgcol);
867 printw("Talon and hand are empty");
870 for (i=0; i<fin; i++) {
871 transit(&hand, &talon);
872 INCRHAND(cnewrow, cnewcol);
873 INCRHAND(coldrow, coldcol);
874 removecard(cnewcol, cnewrow);
876 talon->visible = TRUE;
878 if (talon->paid == FALSE && talon->visible == TRUE) {
879 this.information += costofinformation;
880 game.information += costofinformation;
881 total.information += costofinformation;
884 printcard(coldcol, coldrow, talon);
888 printcard(taloncol, talonrow, talon);
892 move(handstatrow, handstatcol);
893 printw("%3d", cinhand);
894 move(talonstatrow, talonstatcol);
895 printw("%3d", taloncnt);
897 fndbase(&talon, taloncol, talonrow);
903 * procedure to print card counting info on screen
908 register struct cardtype *ptr;
912 move(talonstatrow, talonstatcol - 7);
913 printw("Talon: %3d", taloncnt);
914 move(handstatrow, handstatcol - 7);
915 printw("Hand: %3d", cinhand);
916 move(stockstatrow, stockstatcol - 7);
917 printw("Stock: %3d", stockcnt);
918 for ( row = coldrow, col = coldcol, ptr = talon;
921 if (ptr->paid == FALSE && ptr->visible == TRUE) {
923 this.information += costofinformation;
924 game.information += costofinformation;
925 total.information += costofinformation;
927 printcard(col, row, ptr);
930 for ( row = cnewrow, col = cnewcol, ptr = hand;
933 if (ptr->paid == FALSE && ptr->visible == TRUE) {
935 this.information += costofinformation;
936 game.information += costofinformation;
937 total.information += costofinformation;
940 printcard(col, row, ptr);
945 * procedure to clear card counting info from screen
951 move(talonstatrow, talonstatcol - 7);
953 move(handstatrow, handstatcol - 7);
955 move(stockstatrow, stockstatcol - 7);
957 for ( row = ctoprow ; row <= cbotrow ; row++ ) {
964 * procedure to update card counting base
968 removecard(coldcol, coldrow);
969 DECRHAND(coldrow, coldcol);
970 if (talon != NIL && (talon->visible == FALSE)) {
971 talon->visible = TRUE;
973 this.information += costofinformation;
974 game.information += costofinformation;
975 total.information += costofinformation;
977 printcard(coldcol, coldrow, talon);
982 move(talonstatrow, talonstatcol);
983 printw("%3d", taloncnt);
988 * procedure to update stock card counting base
994 move(stockstatrow, stockstatcol);
995 printw("%3d", stockcnt);
1000 * let 'em know how they lost!
1004 register struct cardtype *ptr;
1007 if (!Cflag || cardsoff == 52)
1009 for (ptr = talon; ptr != NIL; ptr = ptr->next) {
1010 ptr->visible = TRUE;
1013 for (ptr = hand; ptr != NIL; ptr = ptr->next) {
1014 ptr->visible = TRUE;
1018 move(stockrow + 1, sidecol);
1020 move(talonrow - 2, sidecol);
1022 move(talonrow - 1, sidecol);
1024 move(talonrow, sidecol);
1026 move(talonrow + 1, sidecol);
1028 for (ptr = stock, row = stockrow; ptr != NIL; ptr = ptr->next, row++) {
1029 move(row, stockcol - 1);
1031 printcard(stockcol, row, ptr);
1034 move(row, stockcol - 1);
1038 move(handstatrow, handstatcol - 7);
1040 move(row, stockcol - 1);
1042 if ( cardsoff == 52 )
1043 getcmd(moverow, movecol, "Hit return to exit");
1047 * procedure to update the betting values
1051 long thiscosts, gamecosts, totalcosts;
1052 double thisreturn, gamereturn, totalreturn;
1054 register long dollars;
1057 dollars = (now - acctstart) / secondsperdollar;
1059 acctstart += dollars * secondsperdollar;
1060 if (dollars > maxtimecharge)
1061 dollars = maxtimecharge;
1062 this.thinktime += dollars;
1063 game.thinktime += dollars;
1064 total.thinktime += dollars;
1066 thiscosts = this.hand + this.inspection + this.game +
1067 this.runs + this.information + this.thinktime;
1068 gamecosts = game.hand + game.inspection + game.game +
1069 game.runs + game.information + game.thinktime;
1070 totalcosts = total.hand + total.inspection + total.game +
1071 total.runs + total.information + total.thinktime;
1072 this.worth = this.wins - thiscosts;
1073 game.worth = game.wins - gamecosts;
1074 total.worth = total.wins - totalcosts;
1075 thisreturn = ((double)this.wins / (double)thiscosts - 1.0) * 100.0;
1076 gamereturn = ((double)game.wins / (double)gamecosts - 1.0) * 100.0;
1077 totalreturn = ((double)total.wins / (double)totalcosts - 1.0) * 100.0;
1078 if (status != BETTINGBOX)
1080 move(tboxrow + 2, boxcol + 13);
1081 printw("%4d%8d%9d", this.hand, game.hand, total.hand);
1082 move(tboxrow + 3, boxcol + 13);
1083 printw("%4d%8d%9d", this.inspection, game.inspection, total.inspection);
1084 move(tboxrow + 4, boxcol + 13);
1085 printw("%4d%8d%9d", this.game, game.game, total.game);
1086 move(tboxrow + 5, boxcol + 13);
1087 printw("%4d%8d%9d", this.runs, game.runs, total.runs);
1088 move(tboxrow + 6, boxcol + 13);
1089 printw("%4d%8d%9d", this.information, game.information,
1091 move(tboxrow + 7, boxcol + 13);
1092 printw("%4d%8d%9d", this.thinktime, game.thinktime, total.thinktime);
1093 move(tboxrow + 8, boxcol + 13);
1094 printw("%4d%8d%9d", thiscosts, gamecosts, totalcosts);
1095 move(tboxrow + 9, boxcol + 13);
1096 printw("%4d%8d%9d", this.wins, game.wins, total.wins);
1097 move(tboxrow + 10, boxcol + 13);
1098 printw("%4d%8d%9d", this.worth, game.worth, total.worth);
1099 move(tboxrow + 11, boxcol + 13);
1100 printw("%4.0f%%%7.1f%%%8.1f%%", thisreturn, gamereturn, totalreturn);
1104 * procedure to move a card from the stock or talon to the tableau
1106 simpletableau(cp, des)
1107 struct cardtype **cp;
1111 if (notempty(*cp)) {
1112 if (tabok(*cp, des)) {
1117 if (tableau[des] == NIL)
1119 transit(cp, &tableau[des]);
1121 printcard(pilemap[des], length[des], tableau[des]);
1123 if (origin == stk) {
1125 printcard(stockcol, stockrow, stock);
1128 printcard(taloncol, talonrow, talon);
1140 int dlength, slength, i;
1141 struct cardtype *tempcard;
1143 for (i=tabrow; i<=length[sour]; i++)
1144 removecard(pilemap[sour], i);
1145 dlength = length[des] + 1;
1146 slength = length[sour];
1147 if (slength == tabrow)
1148 printcard(pilemap[des], dlength, tableau[sour]);
1150 while (slength != tabrow - 1) {
1151 tempcard = tableau[sour];
1152 for (i=1; i<=slength-tabrow; i++)
1153 tempcard = tempcard->next;
1154 printcard(pilemap[des], dlength, tempcard);
1161 * procedure to move from the tableau to the tableau
1164 register int sour, des;
1166 struct cardtype *temp;
1168 if (notempty(tableau[sour])) {
1169 if (tabok(bottom[sour], des)) {
1170 tabprint(sour, des);
1171 temp = bottom[sour];
1173 if (bottom[des] == NIL)
1175 temp->next = tableau[des];
1176 tableau[des] = tableau[sour];
1177 tableau[sour] = NIL;
1178 length[des] = length[des] + (length[sour] - (tabrow - 1));
1179 length[sour] = tabrow - 1;
1187 * functions to see if the card can go onto the foundation
1191 struct cardtype *cp;
1193 if (found[let]->rank == King)
1194 if (cp->rank == Ace)
1198 else if (cp->rank - 1 == found[let]->rank)
1205 * function to determine if two cards are the same suit
1208 struct cardtype *cp;
1210 if (cp->suit == found[let]->suit)
1217 * procedure to move a card to the correct foundation pile
1219 movetofound(cp, source)
1220 struct cardtype **cp;
1224 if (notempty(*cp)) {
1226 if (found[tempbase] != NIL)
1227 if (rankhigher(*cp, tempbase)
1228 && samesuit(*cp, tempbase)) {
1231 else if (*cp == talon)
1235 transit(cp, &found[tempbase]);
1236 printcard(pilemap[tempbase],
1237 foundrow, found[tempbase]);
1239 if (mtforigin == stk) {
1241 printcard(stockcol, stockrow, stock);
1242 } else if (mtforigin == tal) {
1244 printcard(taloncol, talonrow, talon);
1246 removecard(pilemap[source], length[source]);
1251 this.wins += valuepercardup;
1252 game.wins += valuepercardup;
1253 total.wins += valuepercardup;
1260 } while ((tempbase != 4) && !mtfdone);
1267 * procedure to get a command
1269 getcmd(row, col, cp)
1278 printw("%-24s", cp);
1279 col += 1 + strlen(cp);
1283 ch = getch() & 0177;
1284 if (ch >= 'A' && ch <= 'Z')
1289 } else if (i >= 2 && ch != erasechar() && ch != killchar()) {
1290 if (ch != '\n' && ch != '\r' && ch != ' ')
1291 write(1, "\007", 1);
1292 } else if (ch == erasechar() && i > 0) {
1296 } else if (ch == killchar() && i > 0) {
1302 } else if (ch == '\032') { /* Control-Z */
1306 } else if (isprint(ch)) {
1311 } while (ch != '\n' && ch != '\r' && ch != ' ');
1317 * Suspend the game (shell escape if no process control on system)
1325 updatebettinginfo();
1329 lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1330 write(dbfd, (char *)&total, sizeof(total));
1332 kill(getpid(), SIGTSTP);
1338 * procedure to evaluate and make the specific moves
1343 char osrcpile, odestpile;
1348 if (talon == NIL && hand != NIL)
1350 if (cardsoff == 52) {
1353 } else if (!startedgame) {
1354 move(msgrow, msgcol);
1356 switch (34 - taloncnt - cinhand) {
1361 printw("One card used from talon ");
1364 printw("Two cards used from talon ");
1367 printw(">3< cards used from talon ");
1370 getcmd(moverow, movecol, "Move:");
1372 getcmd(moverow, movecol, "Move:");
1374 if (srcpile >= '1' && srcpile <= '4')
1375 source = (int) (srcpile - '1');
1376 if (destpile >= '1' && destpile <= '4')
1377 dest = (int) (destpile - '1');
1379 (srcpile == 't' || srcpile == 's' || srcpile == 'h' ||
1380 srcpile == '1' || srcpile == '2' || srcpile == '3' ||
1384 odestpile = destpile;
1385 if (status != BETTINGBOX)
1388 getcmd(moverow, movecol, "Inspect game?");
1389 } while (srcpile != 'y' && srcpile != 'n');
1390 if (srcpile == 'n') {
1393 this.inspection += costofinspection;
1394 game.inspection += costofinspection;
1395 total.inspection += costofinspection;
1397 destpile = odestpile;
1402 if (destpile == 'f' || destpile == 'F')
1403 movetofound(&talon, source);
1404 else if (destpile >= '1' && destpile <= '4')
1405 simpletableau(&talon, dest);
1410 if (destpile == 'f' || destpile == 'F')
1411 movetofound(&stock, source);
1412 else if (destpile >= '1' && destpile <= '4')
1413 simpletableau(&stock, dest);
1417 if (destpile != 't' && destpile != 'T') {
1425 if (status == BETTINGBOX) {
1427 getcmd(moverow, movecol,
1429 } while (srcpile != 'y' &&
1431 if (srcpile == 'n') {
1438 this.wins += valuepercardup * cardsoff;
1439 game.wins += valuepercardup * cardsoff;
1440 total.wins += valuepercardup * cardsoff;
1441 this.game += costofgame;
1442 game.game += costofgame;
1443 total.game += costofgame;
1451 printtopbettingbox();
1452 printbottombettingbox();
1453 status = BETTINGBOX;
1456 clearabovemovebox();
1457 clearbelowmovebox();
1461 printtopinstructions();
1462 printbottominstructions();
1463 status = INSTRUCTIONBOX;
1472 case '1': case '2': case '3': case '4':
1473 if (destpile == 'f' || destpile == 'F')
1474 movetofound(&tableau[source], source);
1475 else if (destpile >= '1' && destpile <= '4')
1476 tabtotab(source, dest);
1482 fndbase(&stock, stockcol, stockrow);
1483 fndbase(&talon, taloncol, talonrow);
1484 updatebettinginfo();
1488 char *basicinstructions[] = {
1489 "Here are brief instuctions to the game of Canfield:\n\n",
1490 " If you have never played solitaire before, it is recom-\n",
1491 "mended that you consult a solitaire instruction book. In\n",
1492 "Canfield, tableau cards may be built on each other downward\n",
1493 "in alternate colors. An entire pile must be moved as a unit\n",
1494 "in building. Top cards of the piles are available to be able\n",
1495 "to be played on foundations, but never into empty spaces.\n\n",
1496 " Spaces must be filled from the stock. The top card of\n",
1497 "the stock also is available to be played on foundations or\n",
1498 "built on tableau piles. After the stock is exhausted, ta-\n",
1499 "bleau spaces may be filled from the talon and the player may\n",
1500 "keep them open until he wishes to use them.\n\n",
1501 " Cards are dealt from the hand to the talon by threes\n",
1502 "and this repeats until there are no more cards in the hand\n",
1503 "or the player quits. To have cards dealt onto the talon the\n",
1504 "player types 'ht' for his move. Foundation base cards are\n",
1505 "also automatically moved to the foundation when they become\n",
1507 "push any key when you are finished: ",
1510 char *bettinginstructions[] = {
1511 " The rules for betting are somewhat less strict than\n",
1512 "those used in the official version of the game. The initial\n",
1513 "deal costs $13. You may quit at this point or inspect the\n",
1514 "game. Inspection costs $13 and allows you to make as many\n",
1515 "moves as is possible without moving any cards from your hand\n",
1516 "to the talon. (the initial deal places three cards on the\n",
1517 "talon; if all these cards are used, three more are made\n",
1518 "available) Finally, if the game seems interesting, you must\n",
1519 "pay the final installment of $26. At this point you are\n",
1520 "credited at the rate of $5 for each card on the foundation;\n",
1521 "as the game progresses you are credited with $5 for each\n",
1522 "card that is moved to the foundation. Each run through the\n",
1523 "hand after the first costs $5. The card counting feature\n",
1524 "costs $1 for each unknown card that is identified. If the\n",
1525 "information is toggled on, you are only charged for cards\n",
1526 "that became visible since it was last turned on. Thus the\n",
1527 "maximum cost of information is $34. Playing time is charged\n",
1528 "at a rate of $1 per minute.\n\n",
1529 "push any key when you are finished: ",
1533 * procedure to printout instructions
1539 move(originrow, origincol);
1540 printw("This is the game of solitaire called Canfield. Do\n");
1541 printw("you want instructions for the game?");
1543 getcmd(originrow + 3, origincol, "y or n?");
1544 } while (srcpile != 'y' && srcpile != 'n');
1548 for (cp = basicinstructions; *cp != 0; cp++)
1553 move(originrow, origincol);
1554 printw("Do you want instructions for betting?");
1556 getcmd(originrow + 2, origincol, "y or n?");
1557 } while (srcpile != 'y' && srcpile != 'n');
1561 for (cp = bettinginstructions; *cp != 0; cp++)
1568 * procedure to initialize the game
1581 i = lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1587 i = read(dbfd, (char *)&total, sizeof(total));
1596 * procedure to end the game
1603 if (cardsoff == 52) {
1604 getcmd(moverow, movecol, "Hit return to exit");
1607 move(originrow, origincol);
1608 printw("CONGRATULATIONS!\n");
1609 printw("You won the game. That is a feat to be proud of.\n");
1610 row = originrow + 5;
1613 move(msgrow, msgcol);
1614 printw("You got %d card", cardsoff);
1618 move(msgrow, msgcol);
1623 getcmd(row, col, "Play again (y or n)?");
1624 } while (srcpile != 'y' && srcpile != 'n');
1634 * procedure to clean up and exit
1640 total.thinktime += 1;
1642 updatebettinginfo();
1644 lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1645 write(dbfd, (char *)&total, sizeof(total));
1657 * Field an interrupt.
1662 move(msgrow, msgcol);
1663 printw("Really wish to quit? ");
1665 getcmd(moverow, movecol, "y or n?");
1666 } while (srcpile != 'y' && srcpile != 'n');
1670 signal(SIGINT, askquit);
1674 * Can you tell that this used to be a Pascal program?
1678 dbfd = open(_PATH_SCORE, O_RDWR);
1687 if (vec[2] >= MAXLOAD) {
1688 puts("The system load is too high. Try again later.");
1692 signal(SIGINT, askquit);
1693 signal(SIGHUP, cleanup);
1694 signal(SIGTERM, cleanup);