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[] =
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;
203 * The following procedures print the board onto the screen using the
204 * addressible cursor. The end of these procedures will also be
205 * separated from the rest of the program.
207 * procedure to set the move command box
213 printtopbettingbox();
219 printtopinstructions();
222 move(moverow, boxcol);
224 move(msgrow, boxcol);
228 printbottombettingbox();
234 printbottominstructions();
241 * print directions above move box
243 printtopinstructions()
245 move(tboxrow, boxcol);
246 printw("*----------------------------------*");
247 move(tboxrow + 1, boxcol);
249 move(tboxrow + 2, boxcol);
250 printw("|s# = stock to tableau |");
251 move(tboxrow + 3, boxcol);
252 printw("|sf = stock to foundation |");
253 move(tboxrow + 4, boxcol);
254 printw("|t# = talon to tableau |");
255 move(tboxrow + 5, boxcol);
256 printw("|tf = talon to foundation |");
257 move(tboxrow + 6, boxcol);
258 printw("|## = tableau to tableau |");
259 move(tboxrow + 7, boxcol);
260 printw("|#f = tableau to foundation |");
261 move(tboxrow + 8, boxcol);
262 printw("|ht = hand to talon |");
263 move(tboxrow + 9, boxcol);
264 printw("|c = toggle card counting |");
265 move(tboxrow + 10, boxcol);
266 printw("|b = present betting information |");
267 move(tboxrow + 11, boxcol);
268 printw("|q = quit to end the game |");
269 move(tboxrow + 12, boxcol);
270 printw("|==================================|");
274 * Print the betting box.
279 move(tboxrow, boxcol);
280 printw("*----------------------------------*");
281 move(tboxrow + 1, boxcol);
282 printw("|Costs Hand Game Total |");
283 move(tboxrow + 2, boxcol);
285 move(tboxrow + 3, boxcol);
286 printw("| Inspections |");
287 move(tboxrow + 4, boxcol);
289 move(tboxrow + 5, boxcol);
291 move(tboxrow + 6, boxcol);
292 printw("| Information |");
293 move(tboxrow + 7, boxcol);
294 printw("| Think time |");
295 move(tboxrow + 8, boxcol);
296 printw("|Total Costs |");
297 move(tboxrow + 9, boxcol);
298 printw("|Winnings |");
299 move(tboxrow + 10, boxcol);
300 printw("|Net Worth |");
301 move(tboxrow + 11, boxcol);
303 move(tboxrow + 12, boxcol);
304 printw("|==================================|");
308 * clear info above move box
314 for (i = 0; i <= 11; i++) {
315 move(tboxrow + i, boxcol);
318 move(tboxrow + 12, boxcol);
319 printw("*----------------------------------*");
323 * print instructions below move box
325 printbottominstructions()
327 move(bboxrow, boxcol);
328 printw("|Replace # with the number of the |");
329 move(bboxrow + 1, boxcol);
330 printw("|tableau you want. |");
331 move(bboxrow + 2, boxcol);
332 printw("*----------------------------------*");
336 * print betting information below move box
338 printbottombettingbox()
340 move(bboxrow, boxcol);
341 printw("|x = toggle information box |");
342 move(bboxrow + 1, boxcol);
343 printw("|i = list playing instructions |");
344 move(bboxrow + 2, boxcol);
345 printw("*----------------------------------*");
349 * clear info below move box
355 move(bboxrow, boxcol);
356 printw("*----------------------------------*");
357 for (i = 1; i <= 2; i++) {
358 move(bboxrow + i, boxcol);
364 * procedure to put the board on the screen using addressable cursor
370 move(titlerow, titlecol);
371 printw("=-> CANFIELD <-=");
372 move(fttlrow, fttlcol);
373 printw("foundation");
374 move(foundrow - 1, fttlcol);
375 printw("=---= =---= =---= =---=");
376 move(foundrow, fttlcol);
377 printw("| | | | | | | |");
378 move(foundrow + 1, fttlcol);
379 printw("=---= =---= =---= =---=");
380 move(ottlrow, sidecol);
381 printw("stock tableau");
382 move(stockrow - 1, sidecol);
384 move(stockrow, sidecol);
386 move(stockrow + 1, sidecol);
388 move(talonrow - 2, sidecol);
390 move(talonrow - 1, sidecol);
392 move(talonrow, sidecol);
394 move(talonrow + 1, sidecol);
396 move(tabrow - 1, atabcol);
397 printw("-1- -2- -3- -4-");
402 * clean up the board for another game
407 struct cardtype *ptr;
411 for(ptr = stock, row = stockrow;
413 ptr = ptr->next, row++) {
419 move(stockrow + 1, sidecol);
421 move(talonrow - 2, sidecol);
423 move(talonrow - 1, sidecol);
425 move(talonrow + 1, sidecol);
428 move(stockrow, sidecol);
430 move(talonrow, sidecol);
432 move(foundrow, fttlcol);
433 printw("| | | | | | | |");
434 for (cnt = 0; cnt < 4; cnt++) {
449 for(ptr = tableau[cnt], row = tabrow;
451 ptr = ptr->next, row++)
452 removecard(col, row);
457 * procedure to create a deck of cards
460 struct cardtype *deck[];
468 for (scnt=0; scnt<4; scnt++) {
470 for (r=Ace; r<=King; r++) {
474 cards[i].color = colormap[scnt];
482 * procedure to shuffle the deck
485 struct cardtype *deck[];
488 struct cardtype *temp;
490 for (i=0; i<decksize; i++) {
491 deck[i]->visible = FALSE;
492 deck[i]->paid = FALSE;
494 for (i = decksize-1; i>=0; i--) {
495 j = random() % decksize;
505 * procedure to remove the card from the board
514 * procedure to print the cards on the board
516 printrank(a, b, cp, inverse)
526 case 2: case 3: case 4: case 5: case 6: case 7:
527 case 8: case 9: case 10:
528 printw("%d", cp->rank);
547 * procedure to print out a card
555 else if (cp->visible == FALSE) {
559 bool inverse = (cp->suit == 'd' || cp->suit == 'h');
561 printrank(a, b, cp, inverse);
571 * procedure to move the top card from one location to the top
572 * of another location. The pointers always point to the top
575 transit(source, dest)
576 struct cardtype **source, **dest;
578 struct cardtype *temp;
581 *source = (*source)->next;
587 * Procedure to set the cards on the foundation base when available.
588 * Note that it is only called on a foundation pile at the beginning of
589 * the game, so the pile will have exactly one card in it.
591 fndbase(cp, column, row)
592 struct cardtype **cp;
598 if ((*cp)->rank == basecard->rank) {
600 printcard(pilemap[base], foundrow, *cp);
601 if (*cp == tableau[0])
602 length[0] = length[0] - 1;
603 if (*cp == tableau[1])
604 length[1] = length[1] - 1;
605 if (*cp == tableau[2])
606 length[2] = length[2] - 1;
607 if (*cp == tableau[3])
608 length[3] = length[3] - 1;
609 transit(cp, &found[base]);
615 printcard(column, row, *cp);
618 removecard(column, row);
623 this.wins += valuepercardup;
624 game.wins += valuepercardup;
625 total.wins += valuepercardup;
629 } while (nomore == FALSE);
633 * procedure to initialize the things necessary for the game
639 for (i=0; i<18; i++) {
640 deck[i]->visible = TRUE;
641 deck[i]->paid = TRUE;
645 for (i=12; i>=1; i--)
646 deck[i]->next = deck[i - 1];
649 deck[13]->next = NIL;
653 for (i=14; i<18; i++) {
654 tableau[i - 14] = deck[i];
657 for (i=0; i<4; i++) {
658 bottom[i] = tableau[i];
662 for (i=18; i<decksize-1; i++)
663 deck[i]->next = deck[i + 1];
664 deck[decksize-1]->next = NIL;
674 cnewcol = cinitcol + cwidthcol;
678 * procedure to print the beginning cards and to start each game
686 this.hand = costofhand;
687 game.hand += costofhand;
688 total.hand += costofhand;
692 this.information = 0;
697 printcard(foundcol, foundrow, found[0]);
698 printcard(stockcol, stockrow, stock);
699 printcard(atabcol, tabrow, tableau[0]);
700 printcard(btabcol, tabrow, tableau[1]);
701 printcard(ctabcol, tabrow, tableau[2]);
702 printcard(dtabcol, tabrow, tableau[3]);
703 printcard(taloncol, talonrow, talon);
704 move(foundrow - 2, basecol);
706 move(foundrow - 1, basecol);
708 printrank(basecol, foundrow, found[0], 0);
710 fndbase(&tableau[j], pilemap[j], tabrow);
711 fndbase(&stock, stockcol, stockrow);
712 showstat(); /* show card counting info to cheaters */
718 * procedure to clear the message printed from an error
724 if (errmsg == TRUE) {
726 move(msgrow, msgcol);
734 * procedure to print an error message if the move is not listed
739 move(msgrow, msgcol);
740 printw("Not a proper move ");
744 * procedure to print an error message if the move is not possible
749 move(msgrow, msgcol);
750 printw("Error: Can't move there");
754 * function to see if the source has cards in it
762 move(msgrow, msgcol);
763 printw("Error: no cards to move");
770 * function to see if the rank of one card is less than another
774 struct cardtype *cp1, *cp2;
776 if (cp2->rank == Ace)
777 if (cp1->rank == King)
781 else if (cp1->rank + 1 == cp2->rank)
788 * function to check the cardcolor for moving to a tableau
792 struct cardtype *cp1, *cp2;
794 if (cp1->color == cp2->color)
801 * function to see if the card can move to the tableau
807 if ((cp == stock) && (tableau[des] == NIL))
809 else if (tableau[des] == NIL)
811 cp != bottom[0] && cp != bottom[1] &&
812 cp != bottom[2] && cp != bottom[3])
816 else if (ranklower(cp, tableau[des]) && diffcolor(cp, tableau[des]))
823 * procedure to turn the cards onto the talon from the deck
829 if (cinhand <= 3 && cinhand > 0) {
830 move(msgrow, msgcol);
831 printw("Hand is now empty ");
835 else if (cinhand > 0)
837 else if (talon != NIL) {
840 move(msgrow, msgcol);
841 if (timesthru != 4) {
842 printw("Talon is now the new hand");
843 this.runs += costofrunthroughhand;
844 game.runs += costofrunthroughhand;
845 total.runs += costofrunthroughhand;
846 while (talon != NIL) {
847 transit(&talon, &hand);
858 cnewcol = cinitcol + cwidthcol;
864 printw("I believe you have lost");
870 move(msgrow, msgcol);
871 printw("Talon and hand are empty");
874 for (i=0; i<fin; i++) {
875 transit(&hand, &talon);
876 INCRHAND(cnewrow, cnewcol);
877 INCRHAND(coldrow, coldcol);
878 removecard(cnewcol, cnewrow);
880 talon->visible = TRUE;
882 if (talon->paid == FALSE && talon->visible == TRUE) {
883 this.information += costofinformation;
884 game.information += costofinformation;
885 total.information += costofinformation;
888 printcard(coldcol, coldrow, talon);
892 printcard(taloncol, talonrow, talon);
896 move(handstatrow, handstatcol);
897 printw("%3d", cinhand);
898 move(talonstatrow, talonstatcol);
899 printw("%3d", taloncnt);
901 fndbase(&talon, taloncol, talonrow);
907 * procedure to print card counting info on screen
912 struct cardtype *ptr;
916 move(talonstatrow, talonstatcol - 7);
917 printw("Talon: %3d", taloncnt);
918 move(handstatrow, handstatcol - 7);
919 printw("Hand: %3d", cinhand);
920 move(stockstatrow, stockstatcol - 7);
921 printw("Stock: %3d", stockcnt);
922 for ( row = coldrow, col = coldcol, ptr = talon;
925 if (ptr->paid == FALSE && ptr->visible == TRUE) {
927 this.information += costofinformation;
928 game.information += costofinformation;
929 total.information += costofinformation;
931 printcard(col, row, ptr);
934 for ( row = cnewrow, col = cnewcol, ptr = hand;
937 if (ptr->paid == FALSE && ptr->visible == TRUE) {
939 this.information += costofinformation;
940 game.information += costofinformation;
941 total.information += costofinformation;
944 printcard(col, row, ptr);
949 * procedure to clear card counting info from screen
955 move(talonstatrow, talonstatcol - 7);
957 move(handstatrow, handstatcol - 7);
959 move(stockstatrow, stockstatcol - 7);
961 for ( row = ctoprow ; row <= cbotrow ; row++ ) {
968 * procedure to update card counting base
972 removecard(coldcol, coldrow);
973 DECRHAND(coldrow, coldcol);
974 if (talon != NIL && (talon->visible == FALSE)) {
975 talon->visible = TRUE;
977 this.information += costofinformation;
978 game.information += costofinformation;
979 total.information += costofinformation;
981 printcard(coldcol, coldrow, talon);
986 move(talonstatrow, talonstatcol);
987 printw("%3d", taloncnt);
992 * procedure to update stock card counting base
998 move(stockstatrow, stockstatcol);
999 printw("%3d", stockcnt);
1004 * let 'em know how they lost!
1008 struct cardtype *ptr;
1011 if (!Cflag || cardsoff == 52)
1013 for (ptr = talon; ptr != NIL; ptr = ptr->next) {
1014 ptr->visible = TRUE;
1017 for (ptr = hand; ptr != NIL; ptr = ptr->next) {
1018 ptr->visible = TRUE;
1022 move(stockrow + 1, sidecol);
1024 move(talonrow - 2, sidecol);
1026 move(talonrow - 1, sidecol);
1028 move(talonrow, sidecol);
1030 move(talonrow + 1, sidecol);
1032 for (ptr = stock, row = stockrow; ptr != NIL; ptr = ptr->next, row++) {
1033 move(row, stockcol - 1);
1035 printcard(stockcol, row, ptr);
1038 move(row, stockcol - 1);
1042 move(handstatrow, handstatcol - 7);
1044 move(row, stockcol - 1);
1046 if ( cardsoff == 52 )
1047 getcmd(moverow, movecol, "Hit return to exit");
1051 * procedure to update the betting values
1055 long thiscosts, gamecosts, totalcosts;
1056 double thisreturn, gamereturn, totalreturn;
1061 dollars = (now - acctstart) / secondsperdollar;
1063 acctstart += dollars * secondsperdollar;
1064 if (dollars > maxtimecharge)
1065 dollars = maxtimecharge;
1066 this.thinktime += dollars;
1067 game.thinktime += dollars;
1068 total.thinktime += dollars;
1070 thiscosts = this.hand + this.inspection + this.game +
1071 this.runs + this.information + this.thinktime;
1072 gamecosts = game.hand + game.inspection + game.game +
1073 game.runs + game.information + game.thinktime;
1074 totalcosts = total.hand + total.inspection + total.game +
1075 total.runs + total.information + total.thinktime;
1076 this.worth = this.wins - thiscosts;
1077 game.worth = game.wins - gamecosts;
1078 total.worth = total.wins - totalcosts;
1079 thisreturn = ((double)this.wins / (double)thiscosts - 1.0) * 100.0;
1080 gamereturn = ((double)game.wins / (double)gamecosts - 1.0) * 100.0;
1081 totalreturn = ((double)total.wins / (double)totalcosts - 1.0) * 100.0;
1082 if (status != BETTINGBOX)
1084 move(tboxrow + 2, boxcol + 13);
1085 printw("%4d%8d%9d", this.hand, game.hand, total.hand);
1086 move(tboxrow + 3, boxcol + 13);
1087 printw("%4d%8d%9d", this.inspection, game.inspection, total.inspection);
1088 move(tboxrow + 4, boxcol + 13);
1089 printw("%4d%8d%9d", this.game, game.game, total.game);
1090 move(tboxrow + 5, boxcol + 13);
1091 printw("%4d%8d%9d", this.runs, game.runs, total.runs);
1092 move(tboxrow + 6, boxcol + 13);
1093 printw("%4d%8d%9d", this.information, game.information,
1095 move(tboxrow + 7, boxcol + 13);
1096 printw("%4d%8d%9d", this.thinktime, game.thinktime, total.thinktime);
1097 move(tboxrow + 8, boxcol + 13);
1098 printw("%4d%8d%9d", thiscosts, gamecosts, totalcosts);
1099 move(tboxrow + 9, boxcol + 13);
1100 printw("%4d%8d%9d", this.wins, game.wins, total.wins);
1101 move(tboxrow + 10, boxcol + 13);
1102 printw("%4d%8d%9d", this.worth, game.worth, total.worth);
1103 move(tboxrow + 11, boxcol + 13);
1104 printw("%4.0f%%%7.1f%%%8.1f%%", thisreturn, gamereturn, totalreturn);
1108 * procedure to move a card from the stock or talon to the tableau
1110 simpletableau(cp, des)
1111 struct cardtype **cp;
1115 if (notempty(*cp)) {
1116 if (tabok(*cp, des)) {
1121 if (tableau[des] == NIL)
1123 transit(cp, &tableau[des]);
1125 printcard(pilemap[des], length[des], tableau[des]);
1127 if (origin == stk) {
1129 printcard(stockcol, stockrow, stock);
1132 printcard(taloncol, talonrow, talon);
1144 int dlength, slength, i;
1145 struct cardtype *tempcard;
1147 for (i=tabrow; i<=length[sour]; i++)
1148 removecard(pilemap[sour], i);
1149 dlength = length[des] + 1;
1150 slength = length[sour];
1151 if (slength == tabrow)
1152 printcard(pilemap[des], dlength, tableau[sour]);
1154 while (slength != tabrow - 1) {
1155 tempcard = tableau[sour];
1156 for (i=1; i<=slength-tabrow; i++)
1157 tempcard = tempcard->next;
1158 printcard(pilemap[des], dlength, tempcard);
1165 * procedure to move from the tableau to the tableau
1170 struct cardtype *temp;
1172 if (notempty(tableau[sour])) {
1173 if (tabok(bottom[sour], des)) {
1174 tabprint(sour, des);
1175 temp = bottom[sour];
1177 if (bottom[des] == NIL)
1179 temp->next = tableau[des];
1180 tableau[des] = tableau[sour];
1181 tableau[sour] = NIL;
1182 length[des] = length[des] + (length[sour] - (tabrow - 1));
1183 length[sour] = tabrow - 1;
1191 * functions to see if the card can go onto the foundation
1195 struct cardtype *cp;
1197 if (found[let]->rank == King)
1198 if (cp->rank == Ace)
1202 else if (cp->rank - 1 == found[let]->rank)
1209 * function to determine if two cards are the same suit
1212 struct cardtype *cp;
1214 if (cp->suit == found[let]->suit)
1221 * procedure to move a card to the correct foundation pile
1223 movetofound(cp, source)
1224 struct cardtype **cp;
1228 if (notempty(*cp)) {
1230 if (found[tempbase] != NIL)
1231 if (rankhigher(*cp, tempbase)
1232 && samesuit(*cp, tempbase)) {
1235 else if (*cp == talon)
1239 transit(cp, &found[tempbase]);
1240 printcard(pilemap[tempbase],
1241 foundrow, found[tempbase]);
1243 if (mtforigin == stk) {
1245 printcard(stockcol, stockrow, stock);
1246 } else if (mtforigin == tal) {
1248 printcard(taloncol, talonrow, talon);
1250 removecard(pilemap[source], length[source]);
1255 this.wins += valuepercardup;
1256 game.wins += valuepercardup;
1257 total.wins += valuepercardup;
1264 } while ((tempbase != 4) && !mtfdone);
1271 * procedure to get a command
1273 getcmd(row, col, cp)
1282 printw("%-24s", cp);
1283 col += 1 + strlen(cp);
1287 ch = getch() & 0177;
1288 if (ch >= 'A' && ch <= 'Z')
1293 } else if (i >= 2 && ch != erasechar() && ch != killchar()) {
1294 if (ch != '\n' && ch != '\r' && ch != ' ')
1295 write(1, "\007", 1);
1296 } else if (ch == erasechar() && i > 0) {
1300 } else if (ch == killchar() && i > 0) {
1306 } else if (ch == '\032') { /* Control-Z */
1310 } else if (isprint(ch)) {
1315 } while (ch != '\n' && ch != '\r' && ch != ' ');
1321 * Suspend the game (shell escape if no process control on system)
1329 updatebettinginfo();
1333 lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1334 write(dbfd, (char *)&total, sizeof(total));
1336 kill(getpid(), SIGTSTP);
1342 * procedure to evaluate and make the specific moves
1347 char osrcpile, odestpile;
1352 if (talon == NIL && hand != NIL)
1354 if (cardsoff == 52) {
1357 } else if (!startedgame) {
1358 move(msgrow, msgcol);
1360 switch (34 - taloncnt - cinhand) {
1365 printw("One card used from talon ");
1368 printw("Two cards used from talon ");
1371 printw(">3< cards used from talon ");
1374 getcmd(moverow, movecol, "Move:");
1376 getcmd(moverow, movecol, "Move:");
1378 if (srcpile >= '1' && srcpile <= '4')
1379 source = (int) (srcpile - '1');
1380 if (destpile >= '1' && destpile <= '4')
1381 dest = (int) (destpile - '1');
1383 (srcpile == 't' || srcpile == 's' || srcpile == 'h' ||
1384 srcpile == '1' || srcpile == '2' || srcpile == '3' ||
1388 odestpile = destpile;
1389 if (status != BETTINGBOX)
1392 getcmd(moverow, movecol, "Inspect game?");
1393 } while (srcpile != 'y' && srcpile != 'n');
1394 if (srcpile == 'n') {
1397 this.inspection += costofinspection;
1398 game.inspection += costofinspection;
1399 total.inspection += costofinspection;
1401 destpile = odestpile;
1406 if (destpile == 'f' || destpile == 'F')
1407 movetofound(&talon, source);
1408 else if (destpile >= '1' && destpile <= '4')
1409 simpletableau(&talon, dest);
1414 if (destpile == 'f' || destpile == 'F')
1415 movetofound(&stock, source);
1416 else if (destpile >= '1' && destpile <= '4')
1417 simpletableau(&stock, dest);
1421 if (destpile != 't' && destpile != 'T') {
1429 if (status == BETTINGBOX) {
1431 getcmd(moverow, movecol,
1433 } while (srcpile != 'y' &&
1435 if (srcpile == 'n') {
1442 this.wins += valuepercardup * cardsoff;
1443 game.wins += valuepercardup * cardsoff;
1444 total.wins += valuepercardup * cardsoff;
1445 this.game += costofgame;
1446 game.game += costofgame;
1447 total.game += costofgame;
1455 printtopbettingbox();
1456 printbottombettingbox();
1457 status = BETTINGBOX;
1460 clearabovemovebox();
1461 clearbelowmovebox();
1465 printtopinstructions();
1466 printbottominstructions();
1467 status = INSTRUCTIONBOX;
1476 case '1': case '2': case '3': case '4':
1477 if (destpile == 'f' || destpile == 'F')
1478 movetofound(&tableau[source], source);
1479 else if (destpile >= '1' && destpile <= '4')
1480 tabtotab(source, dest);
1486 fndbase(&stock, stockcol, stockrow);
1487 fndbase(&talon, taloncol, talonrow);
1488 updatebettinginfo();
1492 char *basicinstructions[] = {
1493 "Here are brief instuctions to the game of Canfield:\n\n",
1494 " If you have never played solitaire before, it is recom-\n",
1495 "mended that you consult a solitaire instruction book. In\n",
1496 "Canfield, tableau cards may be built on each other downward\n",
1497 "in alternate colors. An entire pile must be moved as a unit\n",
1498 "in building. Top cards of the piles are available to be able\n",
1499 "to be played on foundations, but never into empty spaces.\n\n",
1500 " Spaces must be filled from the stock. The top card of\n",
1501 "the stock also is available to be played on foundations or\n",
1502 "built on tableau piles. After the stock is exhausted, ta-\n",
1503 "bleau spaces may be filled from the talon and the player may\n",
1504 "keep them open until he wishes to use them.\n\n",
1505 " Cards are dealt from the hand to the talon by threes\n",
1506 "and this repeats until there are no more cards in the hand\n",
1507 "or the player quits. To have cards dealt onto the talon the\n",
1508 "player types 'ht' for his move. Foundation base cards are\n",
1509 "also automatically moved to the foundation when they become\n",
1511 "push any key when you are finished: ",
1514 char *bettinginstructions[] = {
1515 " The rules for betting are somewhat less strict than\n",
1516 "those used in the official version of the game. The initial\n",
1517 "deal costs $13. You may quit at this point or inspect the\n",
1518 "game. Inspection costs $13 and allows you to make as many\n",
1519 "moves as is possible without moving any cards from your hand\n",
1520 "to the talon. (the initial deal places three cards on the\n",
1521 "talon; if all these cards are used, three more are made\n",
1522 "available) Finally, if the game seems interesting, you must\n",
1523 "pay the final installment of $26. At this point you are\n",
1524 "credited at the rate of $5 for each card on the foundation;\n",
1525 "as the game progresses you are credited with $5 for each\n",
1526 "card that is moved to the foundation. Each run through the\n",
1527 "hand after the first costs $5. The card counting feature\n",
1528 "costs $1 for each unknown card that is identified. If the\n",
1529 "information is toggled on, you are only charged for cards\n",
1530 "that became visible since it was last turned on. Thus the\n",
1531 "maximum cost of information is $34. Playing time is charged\n",
1532 "at a rate of $1 per minute.\n\n",
1533 "push any key when you are finished: ",
1537 * procedure to printout instructions
1543 move(originrow, origincol);
1544 printw("This is the game of solitaire called Canfield. Do\n");
1545 printw("you want instructions for the game?");
1547 getcmd(originrow + 3, origincol, "y or n?");
1548 } while (srcpile != 'y' && srcpile != 'n');
1552 for (cp = basicinstructions; *cp != 0; cp++)
1557 move(originrow, origincol);
1558 printw("Do you want instructions for betting?");
1560 getcmd(originrow + 2, origincol, "y or n?");
1561 } while (srcpile != 'y' && srcpile != 'n');
1565 for (cp = bettinginstructions; *cp != 0; cp++)
1572 * procedure to initialize the game
1585 i = lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1591 i = read(dbfd, (char *)&total, sizeof(total));
1600 * procedure to end the game
1607 if (cardsoff == 52) {
1608 getcmd(moverow, movecol, "Hit return to exit");
1611 move(originrow, origincol);
1612 printw("CONGRATULATIONS!\n");
1613 printw("You won the game. That is a feat to be proud of.\n");
1614 row = originrow + 5;
1617 move(msgrow, msgcol);
1618 printw("You got %d card", cardsoff);
1622 move(msgrow, msgcol);
1627 getcmd(row, col, "Play again (y or n)?");
1628 } while (srcpile != 'y' && srcpile != 'n');
1638 * procedure to clean up and exit
1644 total.thinktime += 1;
1646 updatebettinginfo();
1648 lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1649 write(dbfd, (char *)&total, sizeof(total));
1661 * Field an interrupt.
1666 move(msgrow, msgcol);
1667 printw("Really wish to quit? ");
1669 getcmd(moverow, movecol, "y or n?");
1670 } while (srcpile != 'y' && srcpile != 'n');
1674 signal(SIGINT, askquit);
1678 * Can you tell that this used to be a Pascal program?
1682 dbfd = open(_PATH_SCORE, O_RDWR);
1691 if (vec[2] >= MAXLOAD) {
1692 puts("The system load is too high. Try again later.");
1696 signal(SIGINT, askquit);
1697 signal(SIGHUP, cleanup);
1698 signal(SIGTERM, cleanup);