]>
git.cameronkatri.com Git - bsdgames-darwin.git/blob - canfield/canfield/canfield.c
1 /* $NetBSD: canfield.c,v 1.22 2006/02/25 02:06:08 wiz Exp $ */
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
34 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\n\
35 The Regents of the University of California. All rights reserved.\n");
40 static char sccsid
[] = "@(#)canfield.c 8.1 (Berkeley) 5/31/93";
42 __RCSID("$NetBSD: canfield.c,v 1.22 2006/02/25 02:06:08 wiz Exp $");
47 * The canfield program
50 * Originally written: Steve Levine
51 * Converted to use curses and debugged: Steve Feldman
52 * Card counting: Kirk McKusick and Mikey Olson
53 * User interface cleanups: Eric Allman and Kirk McKusick
54 * Betting by Kirk McKusick
57 #include <sys/types.h>
69 #include "pathnames.h"
100 #define handstatrow 21
101 #define handstatcol 7
102 #define talonstatrow 22
103 #define talonstatcol 7
104 #define stockstatrow 23
105 #define stockstatcol 7
125 #define INCRHAND(row, col) {\
127 if (row < ctoprow) {\
132 #define DECRHAND(row, col) {\
134 if (row > cbotrow) {\
147 struct cardtype
*next
;
150 #define NIL ((struct cardtype *) -1)
152 struct cardtype
*deck
[decksize
];
153 struct cardtype cards
[decksize
];
154 struct cardtype
*bottom
[4], *found
[4], *tableau
[4];
155 struct cardtype
*talon
, *hand
, *stock
, *basecard
;
157 int cardsoff
, base
, cinhand
, taloncnt
, stockcnt
, timesthru
;
158 char suitmap
[4] = {spades
, clubs
, hearts
, diamonds
};
159 char colormap
[4] = {black
, black
, red
, red
};
160 char pilemap
[4] = {atabcol
, btabcol
, ctabcol
, dtabcol
};
161 char srcpile
, destpile
;
162 int mtforigin
, tempbase
;
163 int coldcol
, cnewcol
, coldrow
, cnewrow
;
165 bool mtfdone
, Cflag
= FALSE
;
166 #define INSTRUCTIONBOX 1
169 int status
= INSTRUCTIONBOX
;
173 * Basic betting costs
175 #define costofhand 13
176 #define costofinspection 13
177 #define costofgame 26
178 #define costofrunthroughhand 5
179 #define costofinformation 1
180 #define secondsperdollar 60
181 #define maxtimecharge 3
182 #define valuepercardup 5
184 * Variables associated with betting
187 long hand
; /* cost of dealing hand */
188 long inspection
; /* cost of inspecting hand */
189 long game
; /* cost of buying game */
190 long runs
; /* cost of running through hands */
191 long information
; /* cost of information */
192 long thinktime
; /* cost of thinking time */
193 long wins
; /* total winnings */
194 long worth
; /* net worth after costs */
196 struct betinfo
this, game
, total
;
197 bool startedgame
= FALSE
, infullgame
= FALSE
;
202 void cleanup(int) __attribute__((__noreturn__
));
203 void cleanupboard(void);
204 void clearabovemovebox(void);
205 void clearbelowmovebox(void);
207 void clearstat(void);
208 void destinerror(void);
209 bool diffcolor(const struct cardtype
*, const struct cardtype
*);
210 void dumberror(void);
212 void fndbase(struct cardtype
**, int, int);
213 void getcmd(int, int, const char *);
215 void initdeck(struct cardtype
*[]);
219 void makeboard(void);
222 void movetofound(struct cardtype
**, int);
223 void movetotalon(void);
224 bool notempty(const struct cardtype
*);
225 void printbottombettingbox(void);
226 void printbottominstructions(void);
227 void printcard(int, int, const struct cardtype
*);
228 void printrank(int, int, const struct cardtype
*, bool);
229 void printtopbettingbox(void);
230 void printtopinstructions(void);
231 bool rankhigher(const struct cardtype
*, int);
232 bool ranklower(const struct cardtype
*, const struct cardtype
*);
233 void removecard(int, int);
234 int samesuit(const struct cardtype
*, int);
235 void showcards(void);
237 void shuffle(struct cardtype
*[]);
238 void simpletableau(struct cardtype
**, int);
239 void startgame(void);
241 bool tabok(const struct cardtype
*, int);
242 void tabprint(int, int);
243 void tabtotab(int, int);
244 void transit(struct cardtype
**, struct cardtype
**);
245 void updatebettinginfo(void);
246 void usedstock(void);
247 void usedtalon(void);
250 * The following procedures print the board onto the screen using the
251 * addressible cursor. The end of these procedures will also be
252 * separated from the rest of the program.
254 * procedure to set the move command box
261 printtopbettingbox();
267 printtopinstructions();
270 move(moverow
, boxcol
);
272 move(msgrow
, boxcol
);
276 printbottombettingbox();
282 printbottominstructions();
289 * print directions above move box
292 printtopinstructions(void)
294 move(tboxrow
, boxcol
);
295 printw("*----------------------------------*");
296 move(tboxrow
+ 1, boxcol
);
298 move(tboxrow
+ 2, boxcol
);
299 printw("|s# = stock to tableau |");
300 move(tboxrow
+ 3, boxcol
);
301 printw("|sf = stock to foundation |");
302 move(tboxrow
+ 4, boxcol
);
303 printw("|t# = talon to tableau |");
304 move(tboxrow
+ 5, boxcol
);
305 printw("|tf = talon to foundation |");
306 move(tboxrow
+ 6, boxcol
);
307 printw("|## = tableau to tableau |");
308 move(tboxrow
+ 7, boxcol
);
309 printw("|#f = tableau to foundation |");
310 move(tboxrow
+ 8, boxcol
);
311 printw("|ht = hand to talon |");
312 move(tboxrow
+ 9, boxcol
);
313 printw("|c = toggle card counting |");
314 move(tboxrow
+ 10, boxcol
);
315 printw("|b = present betting information |");
316 move(tboxrow
+ 11, boxcol
);
317 printw("|q = quit to end the game |");
318 move(tboxrow
+ 12, boxcol
);
319 printw("|==================================|");
323 * Print the betting box.
326 printtopbettingbox(void)
329 move(tboxrow
, boxcol
);
330 printw("*----------------------------------*");
331 move(tboxrow
+ 1, boxcol
);
332 printw("|Costs Hand Game Total |");
333 move(tboxrow
+ 2, boxcol
);
335 move(tboxrow
+ 3, boxcol
);
336 printw("| Inspections |");
337 move(tboxrow
+ 4, boxcol
);
339 move(tboxrow
+ 5, boxcol
);
341 move(tboxrow
+ 6, boxcol
);
342 printw("| Information |");
343 move(tboxrow
+ 7, boxcol
);
344 printw("| Think time |");
345 move(tboxrow
+ 8, boxcol
);
346 printw("|Total Costs |");
347 move(tboxrow
+ 9, boxcol
);
348 printw("|Winnings |");
349 move(tboxrow
+ 10, boxcol
);
350 printw("|Net Worth |");
351 move(tboxrow
+ 11, boxcol
);
353 move(tboxrow
+ 12, boxcol
);
354 printw("|==================================|");
358 * clear info above move box
361 clearabovemovebox(void)
365 for (i
= 0; i
<= 11; i
++) {
366 move(tboxrow
+ i
, boxcol
);
369 move(tboxrow
+ 12, boxcol
);
370 printw("*----------------------------------*");
374 * print instructions below move box
377 printbottominstructions(void)
379 move(bboxrow
, boxcol
);
380 printw("|Replace # with the number of the |");
381 move(bboxrow
+ 1, boxcol
);
382 printw("|tableau you want. |");
383 move(bboxrow
+ 2, boxcol
);
384 printw("*----------------------------------*");
388 * print betting information below move box
391 printbottombettingbox(void)
393 move(bboxrow
, boxcol
);
394 printw("|x = toggle information box |");
395 move(bboxrow
+ 1, boxcol
);
396 printw("|i = list playing instructions |");
397 move(bboxrow
+ 2, boxcol
);
398 printw("*----------------------------------*");
402 * clear info below move box
405 clearbelowmovebox(void)
409 move(bboxrow
, boxcol
);
410 printw("*----------------------------------*");
411 for (i
= 1; i
<= 2; i
++) {
412 move(bboxrow
+ i
, boxcol
);
418 * procedure to put the board on the screen using addressable cursor
425 move(titlerow
, titlecol
);
426 printw("=-> CANFIELD <-=");
427 move(fttlrow
, fttlcol
);
428 printw("foundation");
429 move(foundrow
- 1, fttlcol
);
430 printw("=---= =---= =---= =---=");
431 move(foundrow
, fttlcol
);
432 printw("| | | | | | | |");
433 move(foundrow
+ 1, fttlcol
);
434 printw("=---= =---= =---= =---=");
435 move(ottlrow
, sidecol
);
436 printw("stock tableau");
437 move(stockrow
- 1, sidecol
);
439 move(stockrow
, sidecol
);
441 move(stockrow
+ 1, sidecol
);
443 move(talonrow
- 2, sidecol
);
445 move(talonrow
- 1, sidecol
);
447 move(talonrow
, sidecol
);
449 move(talonrow
+ 1, sidecol
);
451 move(tabrow
- 1, atabcol
);
452 printw("-1- -2- -3- -4-");
457 * clean up the board for another game
463 struct cardtype
*ptr
;
468 for(ptr
= stock
, row
= stockrow
;
470 ptr
= ptr
->next
, row
++) {
476 move(stockrow
+ 1, sidecol
);
478 move(talonrow
- 2, sidecol
);
480 move(talonrow
- 1, sidecol
);
482 move(talonrow
+ 1, sidecol
);
485 move(stockrow
, sidecol
);
487 move(talonrow
, sidecol
);
489 move(foundrow
, fttlcol
);
490 printw("| | | | | | | |");
491 for (cnt
= 0; cnt
< 4; cnt
++) {
506 for(ptr
= tableau
[cnt
], row
= tabrow
;
508 ptr
= ptr
->next
, row
++)
509 removecard(col
, row
);
514 * procedure to create a deck of cards
517 initdeck(struct cardtype
*ideck
[])
525 for (scnt
=0; scnt
<4; scnt
++) {
527 for (r
=Ace
; r
<=King
; r
++) {
528 ideck
[i
] = &cards
[i
];
531 cards
[i
].color
= colormap
[scnt
];
539 * procedure to shuffle the deck
542 shuffle(struct cardtype
*ideck
[])
545 struct cardtype
*temp
;
547 for (i
=0; i
<decksize
; i
++) {
548 ideck
[i
]->visible
= FALSE
;
549 ideck
[i
]->paid
= FALSE
;
551 for (i
= decksize
-1; i
>=0; i
--) {
552 j
= random() % decksize
;
562 * procedure to remove the card from the board
565 removecard(int a
, int b
)
572 * procedure to print the cards on the board
575 printrank(int a
, int b
, const struct cardtype
*cp
, bool inverse
)
583 case 2: case 3: case 4: case 5: case 6: case 7:
584 case 8: case 9: case 10:
585 printw("%d", cp
->rank
);
604 * procedure to print out a card
607 printcard(int a
, int b
, const struct cardtype
*cp
)
611 else if (cp
->visible
== FALSE
) {
615 bool inverse
= (cp
->suit
== 'd' || cp
->suit
== 'h');
617 printrank(a
, b
, cp
, inverse
);
627 * procedure to move the top card from one location to the top
628 * of another location. The pointers always point to the top
632 transit(struct cardtype
**source
, struct cardtype
**dest
)
634 struct cardtype
*temp
;
637 *source
= (*source
)->next
;
643 * Procedure to set the cards on the foundation base when available.
644 * Note that it is only called on a foundation pile at the beginning of
645 * the game, so the pile will have exactly one card in it.
648 fndbase(struct cardtype
**cp
, int column
, int row
)
654 if ((*cp
)->rank
== basecard
->rank
) {
656 printcard(pilemap
[base
], foundrow
, *cp
);
657 if (*cp
== tableau
[0])
658 length
[0] = length
[0] - 1;
659 if (*cp
== tableau
[1])
660 length
[1] = length
[1] - 1;
661 if (*cp
== tableau
[2])
662 length
[2] = length
[2] - 1;
663 if (*cp
== tableau
[3])
664 length
[3] = length
[3] - 1;
665 transit(cp
, &found
[base
]);
671 printcard(column
, row
, *cp
);
674 removecard(column
, row
);
679 this.wins
+= valuepercardup
;
680 game
.wins
+= valuepercardup
;
681 total
.wins
+= valuepercardup
;
685 } while (nomore
== FALSE
);
689 * procedure to initialize the things necessary for the game
696 for (i
=0; i
<18; i
++) {
697 deck
[i
]->visible
= TRUE
;
698 deck
[i
]->paid
= TRUE
;
702 for (i
=12; i
>=1; i
--)
703 deck
[i
]->next
= deck
[i
- 1];
706 deck
[13]->next
= NIL
;
710 for (i
=14; i
<18; i
++) {
711 tableau
[i
- 14] = deck
[i
];
714 for (i
=0; i
<4; i
++) {
715 bottom
[i
] = tableau
[i
];
719 for (i
=18; i
<decksize
-1; i
++)
720 deck
[i
]->next
= deck
[i
+ 1];
721 deck
[decksize
-1]->next
= NIL
;
731 cnewcol
= cinitcol
+ cwidthcol
;
735 * procedure to print the beginning cards and to start each game
744 this.hand
= costofhand
;
745 game
.hand
+= costofhand
;
746 total
.hand
+= costofhand
;
750 this.information
= 0;
755 printcard(foundcol
, foundrow
, found
[0]);
756 printcard(stockcol
, stockrow
, stock
);
757 printcard(atabcol
, tabrow
, tableau
[0]);
758 printcard(btabcol
, tabrow
, tableau
[1]);
759 printcard(ctabcol
, tabrow
, tableau
[2]);
760 printcard(dtabcol
, tabrow
, tableau
[3]);
761 printcard(taloncol
, talonrow
, talon
);
762 move(foundrow
- 2, basecol
);
764 move(foundrow
- 1, basecol
);
766 printrank(basecol
, foundrow
, found
[0], 0);
768 fndbase(&tableau
[j
], pilemap
[j
], tabrow
);
769 fndbase(&stock
, stockcol
, stockrow
);
770 showstat(); /* show card counting info to cheaters */
776 * procedure to clear the message printed from an error
783 if (errmsg
== TRUE
) {
785 move(msgrow
, msgcol
);
793 * procedure to print an error message if the move is not listed
799 move(msgrow
, msgcol
);
800 printw("Not a proper move ");
804 * procedure to print an error message if the move is not possible
810 move(msgrow
, msgcol
);
811 printw("Error: Can't move there");
815 * function to see if the source has cards in it
818 notempty(const struct cardtype
*cp
)
822 move(msgrow
, msgcol
);
823 printw("Error: no cards to move");
830 * function to see if the rank of one card is less than another
833 ranklower(const struct cardtype
*cp1
, const struct cardtype
*cp2
)
835 if (cp2
->rank
== Ace
)
836 if (cp1
->rank
== King
)
840 else if (cp1
->rank
+ 1 == cp2
->rank
)
847 * function to check the cardcolor for moving to a tableau
850 diffcolor(const struct cardtype
*cp1
, const struct cardtype
*cp2
)
852 if (cp1
->color
== cp2
->color
)
859 * function to see if the card can move to the tableau
862 tabok(const struct cardtype
*cp
, int des
)
864 if ((cp
== stock
) && (tableau
[des
] == NIL
))
866 else if (tableau
[des
] == NIL
)
868 cp
!= bottom
[0] && cp
!= bottom
[1] &&
869 cp
!= bottom
[2] && cp
!= bottom
[3])
873 else if (ranklower(cp
, tableau
[des
]) && diffcolor(cp
, tableau
[des
]))
880 * procedure to turn the cards onto the talon from the deck
887 if (cinhand
<= 3 && cinhand
> 0) {
888 move(msgrow
, msgcol
);
889 printw("Hand is now empty ");
893 else if (cinhand
> 0)
895 else if (talon
!= NIL
) {
898 move(msgrow
, msgcol
);
899 if (timesthru
!= 4) {
900 printw("Talon is now the new hand");
901 this.runs
+= costofrunthroughhand
;
902 game
.runs
+= costofrunthroughhand
;
903 total
.runs
+= costofrunthroughhand
;
904 while (talon
!= NIL
) {
905 transit(&talon
, &hand
);
916 cnewcol
= cinitcol
+ cwidthcol
;
922 printw("I believe you have lost");
928 move(msgrow
, msgcol
);
929 printw("Talon and hand are empty");
932 for (i
=0; i
<fin
; i
++) {
933 transit(&hand
, &talon
);
934 INCRHAND(cnewrow
, cnewcol
);
935 INCRHAND(coldrow
, coldcol
);
936 removecard(cnewcol
, cnewrow
);
938 talon
->visible
= TRUE
;
940 if (talon
->paid
== FALSE
&& talon
->visible
== TRUE
) {
941 this.information
+= costofinformation
;
942 game
.information
+= costofinformation
;
943 total
.information
+= costofinformation
;
946 printcard(coldcol
, coldrow
, talon
);
950 printcard(taloncol
, talonrow
, talon
);
954 move(handstatrow
, handstatcol
);
955 printw("%3d", cinhand
);
956 move(talonstatrow
, talonstatcol
);
957 printw("%3d", taloncnt
);
959 fndbase(&talon
, taloncol
, talonrow
);
965 * procedure to print card counting info on screen
972 struct cardtype
*ptr
;
976 move(talonstatrow
, talonstatcol
- 7);
977 printw("Talon: %3d", taloncnt
);
978 move(handstatrow
, handstatcol
- 7);
979 printw("Hand: %3d", cinhand
);
980 move(stockstatrow
, stockstatcol
- 7);
981 printw("Stock: %3d", stockcnt
);
982 for ( row
= coldrow
, col
= coldcol
, ptr
= talon
;
985 if (ptr
->paid
== FALSE
&& ptr
->visible
== TRUE
) {
987 this.information
+= costofinformation
;
988 game
.information
+= costofinformation
;
989 total
.information
+= costofinformation
;
991 printcard(col
, row
, ptr
);
994 for ( row
= cnewrow
, col
= cnewcol
, ptr
= hand
;
997 if (ptr
->paid
== FALSE
&& ptr
->visible
== TRUE
) {
999 this.information
+= costofinformation
;
1000 game
.information
+= costofinformation
;
1001 total
.information
+= costofinformation
;
1004 printcard(col
, row
, ptr
);
1009 * procedure to clear card counting info from screen
1016 move(talonstatrow
, talonstatcol
- 7);
1018 move(handstatrow
, handstatcol
- 7);
1020 move(stockstatrow
, stockstatcol
- 7);
1022 for ( row
= ctoprow
; row
<= cbotrow
; row
++ ) {
1023 move(row
, cinitcol
);
1024 printw("%56s", " ");
1029 * procedure to update card counting base
1034 removecard(coldcol
, coldrow
);
1035 DECRHAND(coldrow
, coldcol
);
1036 if (talon
!= NIL
&& (talon
->visible
== FALSE
)) {
1037 talon
->visible
= TRUE
;
1039 this.information
+= costofinformation
;
1040 game
.information
+= costofinformation
;
1041 total
.information
+= costofinformation
;
1043 printcard(coldcol
, coldrow
, talon
);
1048 move(talonstatrow
, talonstatcol
);
1049 printw("%3d", taloncnt
);
1054 * procedure to update stock card counting base
1061 move(stockstatrow
, stockstatcol
);
1062 printw("%3d", stockcnt
);
1067 * let 'em know how they lost!
1072 struct cardtype
*ptr
;
1075 if (!Cflag
|| cardsoff
== 52)
1077 for (ptr
= talon
; ptr
!= NIL
; ptr
= ptr
->next
) {
1078 ptr
->visible
= TRUE
;
1081 for (ptr
= hand
; ptr
!= NIL
; ptr
= ptr
->next
) {
1082 ptr
->visible
= TRUE
;
1086 move(stockrow
+ 1, sidecol
);
1088 move(talonrow
- 2, sidecol
);
1090 move(talonrow
- 1, sidecol
);
1092 move(talonrow
, sidecol
);
1094 move(talonrow
+ 1, sidecol
);
1096 for (ptr
= stock
, row
= stockrow
; ptr
!= NIL
; ptr
= ptr
->next
, row
++) {
1097 move(row
, stockcol
- 1);
1099 printcard(stockcol
, row
, ptr
);
1102 move(row
, stockcol
- 1);
1106 move(handstatrow
, handstatcol
- 7);
1108 move(row
, stockcol
- 1);
1110 if ( cardsoff
== 52 )
1111 getcmd(moverow
, movecol
, "Hit return to exit");
1115 * procedure to update the betting values
1118 updatebettinginfo(void)
1120 long thiscosts
, gamecosts
, totalcosts
;
1121 double thisreturn
, gamereturn
, totalreturn
;
1126 dollars
= (now
- acctstart
) / secondsperdollar
;
1128 acctstart
+= dollars
* secondsperdollar
;
1129 if (dollars
> maxtimecharge
)
1130 dollars
= maxtimecharge
;
1131 this.thinktime
+= dollars
;
1132 game
.thinktime
+= dollars
;
1133 total
.thinktime
+= dollars
;
1135 thiscosts
= this.hand
+ this.inspection
+ this.game
+
1136 this.runs
+ this.information
+ this.thinktime
;
1137 gamecosts
= game
.hand
+ game
.inspection
+ game
.game
+
1138 game
.runs
+ game
.information
+ game
.thinktime
;
1139 totalcosts
= total
.hand
+ total
.inspection
+ total
.game
+
1140 total
.runs
+ total
.information
+ total
.thinktime
;
1141 this.worth
= this.wins
- thiscosts
;
1142 game
.worth
= game
.wins
- gamecosts
;
1143 total
.worth
= total
.wins
- totalcosts
;
1144 thisreturn
= ((double)this.wins
/ (double)thiscosts
- 1.0) * 100.0;
1145 gamereturn
= ((double)game
.wins
/ (double)gamecosts
- 1.0) * 100.0;
1146 totalreturn
= ((double)total
.wins
/ (double)totalcosts
- 1.0) * 100.0;
1147 if (status
!= BETTINGBOX
)
1149 move(tboxrow
+ 2, boxcol
+ 13);
1150 printw("%4ld%8ld%9ld", this.hand
, game
.hand
, total
.hand
);
1151 move(tboxrow
+ 3, boxcol
+ 13);
1152 printw("%4ld%8ld%9ld", this.inspection
, game
.inspection
,
1154 move(tboxrow
+ 4, boxcol
+ 13);
1155 printw("%4ld%8ld%9ld", this.game
, game
.game
, total
.game
);
1156 move(tboxrow
+ 5, boxcol
+ 13);
1157 printw("%4ld%8ld%9ld", this.runs
, game
.runs
, total
.runs
);
1158 move(tboxrow
+ 6, boxcol
+ 13);
1159 printw("%4ld%8ld%9ld", this.information
, game
.information
,
1161 move(tboxrow
+ 7, boxcol
+ 13);
1162 printw("%4ld%8ld%9ld", this.thinktime
, game
.thinktime
, total
.thinktime
);
1163 move(tboxrow
+ 8, boxcol
+ 13);
1164 printw("%4ld%8ld%9ld", thiscosts
, gamecosts
, totalcosts
);
1165 move(tboxrow
+ 9, boxcol
+ 13);
1166 printw("%4ld%8ld%9ld", this.wins
, game
.wins
, total
.wins
);
1167 move(tboxrow
+ 10, boxcol
+ 13);
1168 printw("%4ld%8ld%9ld", this.worth
, game
.worth
, total
.worth
);
1169 move(tboxrow
+ 11, boxcol
+ 13);
1170 printw("%4.0f%%%7.1f%%%8.1f%%", thisreturn
, gamereturn
, totalreturn
);
1174 * procedure to move a card from the stock or talon to the tableau
1177 simpletableau(struct cardtype
**cp
, int des
)
1181 if (notempty(*cp
)) {
1182 if (tabok(*cp
, des
)) {
1187 if (tableau
[des
] == NIL
)
1189 transit(cp
, &tableau
[des
]);
1191 printcard(pilemap
[des
], length
[des
], tableau
[des
]);
1193 if (origin
== stk
) {
1195 printcard(stockcol
, stockrow
, stock
);
1198 printcard(taloncol
, talonrow
, talon
);
1209 tabprint(int sour
, int des
)
1211 int dlength
, slength
, i
;
1212 struct cardtype
*tempcard
;
1214 for (i
=tabrow
; i
<=length
[sour
]; i
++)
1215 removecard(pilemap
[sour
], i
);
1216 dlength
= length
[des
] + 1;
1217 slength
= length
[sour
];
1218 if (slength
== tabrow
)
1219 printcard(pilemap
[des
], dlength
, tableau
[sour
]);
1221 while (slength
!= tabrow
- 1) {
1222 tempcard
= tableau
[sour
];
1223 for (i
=1; i
<=slength
-tabrow
; i
++)
1224 tempcard
= tempcard
->next
;
1225 printcard(pilemap
[des
], dlength
, tempcard
);
1232 * procedure to move from the tableau to the tableau
1235 tabtotab(int sour
, int des
)
1237 struct cardtype
*temp
;
1239 if (notempty(tableau
[sour
])) {
1240 if (tabok(bottom
[sour
], des
)) {
1241 tabprint(sour
, des
);
1242 temp
= bottom
[sour
];
1244 if (bottom
[des
] == NIL
)
1246 temp
->next
= tableau
[des
];
1247 tableau
[des
] = tableau
[sour
];
1248 tableau
[sour
] = NIL
;
1249 length
[des
] = length
[des
] +
1250 (length
[sour
] - (tabrow
- 1));
1251 length
[sour
] = tabrow
- 1;
1259 * functions to see if the card can go onto the foundation
1262 rankhigher(const struct cardtype
*cp
, int let
)
1264 if (found
[let
]->rank
== King
)
1265 if (cp
->rank
== Ace
)
1269 else if (cp
->rank
- 1 == found
[let
]->rank
)
1276 * function to determine if two cards are the same suit
1279 samesuit(const struct cardtype
*cp
, int let
)
1281 if (cp
->suit
== found
[let
]->suit
)
1288 * procedure to move a card to the correct foundation pile
1291 movetofound(struct cardtype
**cp
, int source
)
1295 if (notempty(*cp
)) {
1297 if (found
[tempbase
] != NIL
)
1298 if (rankhigher(*cp
, tempbase
)
1299 && samesuit(*cp
, tempbase
)) {
1302 else if (*cp
== talon
)
1306 transit(cp
, &found
[tempbase
]);
1307 printcard(pilemap
[tempbase
],
1308 foundrow
, found
[tempbase
]);
1310 if (mtforigin
== stk
) {
1312 printcard(stockcol
, stockrow
,
1314 } else if (mtforigin
== tal
) {
1316 printcard(taloncol
, talonrow
,
1319 removecard(pilemap
[source
],
1325 this.wins
+= valuepercardup
;
1326 game
.wins
+= valuepercardup
;
1327 total
.wins
+= valuepercardup
;
1334 } while ((tempbase
!= 4) && !mtfdone
);
1341 * procedure to get a command
1344 getcmd(int row
, int col
, const char *cp
)
1346 char cmd
[2] = { '\0', '\0'}, ch
;
1351 printw("%-24s", cp
);
1352 col
+= 1 + strlen(cp
);
1356 ch
= getch() & 0177;
1357 if (ch
>= 'A' && ch
<= 'Z')
1362 } else if (i
>= 2 && ch
!= erasechar() && ch
!= killchar()) {
1363 if (ch
!= '\n' && ch
!= '\r' && ch
!= ' ')
1364 write(1, "\007", 1);
1365 } else if (ch
== erasechar() && i
> 0) {
1369 } else if (ch
== killchar() && i
> 0) {
1375 } else if (ch
== '\032') { /* Control-Z */
1379 } else if (isprint((unsigned char)ch
)) {
1384 } while (ch
!= '\n' && ch
!= '\r' && ch
!= ' ');
1390 * Suspend the game (shell escape if no process control on system)
1399 updatebettinginfo();
1403 lseek(dbfd
, uid
* sizeof(struct betinfo
), SEEK_SET
);
1404 write(dbfd
, (char *)&total
, sizeof(total
));
1406 kill(getpid(), SIGTSTP
);
1412 * procedure to evaluate and make the specific moves
1418 char osrcpile
, odestpile
;
1424 if (talon
== NIL
&& hand
!= NIL
)
1426 if (cardsoff
== 52) {
1429 } else if (!startedgame
) {
1430 move(msgrow
, msgcol
);
1432 switch (34 - taloncnt
- cinhand
) {
1437 printw("One card used from talon ");
1440 printw("Two cards used from talon ");
1443 printw(">3< cards used from talon ");
1446 getcmd(moverow
, movecol
, "Move:");
1448 getcmd(moverow
, movecol
, "Move:");
1450 if (srcpile
>= '1' && srcpile
<= '4')
1451 source
= (int) (srcpile
- '1');
1452 if (destpile
>= '1' && destpile
<= '4')
1453 dest
= (int) (destpile
- '1');
1455 (srcpile
== 't' || srcpile
== 's' || srcpile
== 'h' ||
1456 srcpile
== '1' || srcpile
== '2' || srcpile
== '3' ||
1460 odestpile
= destpile
;
1461 if (status
!= BETTINGBOX
)
1464 getcmd(moverow
, movecol
, "Inspect game?");
1465 } while (srcpile
!= 'y' && srcpile
!= 'n');
1466 if (srcpile
== 'n') {
1469 this.inspection
+= costofinspection
;
1470 game
.inspection
+= costofinspection
;
1471 total
.inspection
+= costofinspection
;
1473 destpile
= odestpile
;
1478 if (destpile
== 'f' || destpile
== 'F')
1479 movetofound(&talon
, source
);
1480 else if (destpile
>= '1' && destpile
<= '4')
1481 simpletableau(&talon
, dest
);
1486 if (destpile
== 'f' || destpile
== 'F')
1487 movetofound(&stock
, source
);
1488 else if (destpile
>= '1' && destpile
<= '4')
1489 simpletableau(&stock
, dest
);
1493 if (destpile
!= 't' && destpile
!= 'T') {
1501 if (status
== BETTINGBOX
) {
1503 getcmd(moverow
, movecol
,
1505 } while (srcpile
!= 'y' &&
1507 if (srcpile
== 'n') {
1514 this.wins
+= valuepercardup
* cardsoff
;
1515 game
.wins
+= valuepercardup
* cardsoff
;
1516 total
.wins
+= valuepercardup
* cardsoff
;
1517 this.game
+= costofgame
;
1518 game
.game
+= costofgame
;
1519 total
.game
+= costofgame
;
1527 printtopbettingbox();
1528 printbottombettingbox();
1529 status
= BETTINGBOX
;
1532 clearabovemovebox();
1533 clearbelowmovebox();
1537 printtopinstructions();
1538 printbottominstructions();
1539 status
= INSTRUCTIONBOX
;
1548 case '1': case '2': case '3': case '4':
1549 if (destpile
== 'f' || destpile
== 'F')
1550 movetofound(&tableau
[source
], source
);
1551 else if (destpile
>= '1' && destpile
<= '4')
1552 tabtotab(source
, dest
);
1558 fndbase(&stock
, stockcol
, stockrow
);
1559 fndbase(&talon
, taloncol
, talonrow
);
1560 updatebettinginfo();
1564 const char *const basicinstructions
[] = {
1565 "Here are brief instructions to the game of Canfield:\n\n",
1566 " If you have never played solitaire before, it is recom-\n",
1567 "mended that you consult a solitaire instruction book. In\n",
1568 "Canfield, tableau cards may be built on each other downward\n",
1569 "in alternate colors. An entire pile must be moved as a unit\n",
1570 "in building. Top cards of the piles are available to be able\n",
1571 "to be played on foundations, but never into empty spaces.\n\n",
1572 " Spaces must be filled from the stock. The top card of\n",
1573 "the stock also is available to be played on foundations or\n",
1574 "built on tableau piles. After the stock is exhausted, ta-\n",
1575 "bleau spaces may be filled from the talon and the player may\n",
1576 "keep them open until he wishes to use them.\n\n",
1577 " Cards are dealt from the hand to the talon by threes\n",
1578 "and this repeats until there are no more cards in the hand\n",
1579 "or the player quits. To have cards dealt onto the talon the\n",
1580 "player types 'ht' for his move. Foundation base cards are\n",
1581 "also automatically moved to the foundation when they become\n",
1583 "push any key when you are finished: ",
1586 const char *const bettinginstructions
[] = {
1587 " The rules for betting are somewhat less strict than\n",
1588 "those used in the official version of the game. The initial\n",
1589 "deal costs $13. You may quit at this point or inspect the\n",
1590 "game. Inspection costs $13 and allows you to make as many\n",
1591 "moves as is possible without moving any cards from your hand\n",
1592 "to the talon. (the initial deal places three cards on the\n",
1593 "talon; if all these cards are used, three more are made\n",
1594 "available) Finally, if the game seems interesting, you must\n",
1595 "pay the final installment of $26. At this point you are\n",
1596 "credited at the rate of $5 for each card on the foundation;\n",
1597 "as the game progresses you are credited with $5 for each\n",
1598 "card that is moved to the foundation. Each run through the\n",
1599 "hand after the first costs $5. The card counting feature\n",
1600 "costs $1 for each unknown card that is identified. If the\n",
1601 "information is toggled on, you are only charged for cards\n",
1602 "that became visible since it was last turned on. Thus the\n",
1603 "maximum cost of information is $34. Playing time is charged\n",
1604 "at a rate of $1 per minute.\n\n",
1605 "push any key when you are finished: ",
1609 * procedure to printout instructions
1614 const char *const *cp
;
1616 move(originrow
, origincol
);
1617 printw("This is the game of solitaire called Canfield. Do\n");
1618 printw("you want instructions for the game?");
1620 getcmd(originrow
+ 3, origincol
, "y or n?");
1621 } while (srcpile
!= 'y' && srcpile
!= 'n');
1625 for (cp
= basicinstructions
; *cp
!= 0; cp
++)
1630 move(originrow
, origincol
);
1631 printw("Do you want instructions for betting?");
1633 getcmd(originrow
+ 2, origincol
, "y or n?");
1634 } while (srcpile
!= 'y' && srcpile
!= 'n');
1638 for (cp
= bettinginstructions
; *cp
!= 0; cp
++)
1645 * procedure to initialize the game
1658 dbfd
= open(_PATH_SCORE
, O_RDWR
);
1660 /* Revoke setgid privileges */
1667 i
= lseek(dbfd
, uid
* sizeof(struct betinfo
), SEEK_SET
);
1673 i
= read(dbfd
, (char *)&total
, sizeof(total
));
1682 * procedure to end the game
1689 if (cardsoff
== 52) {
1690 getcmd(moverow
, movecol
, "Hit return to exit");
1693 move(originrow
, origincol
);
1694 printw("CONGRATULATIONS!\n");
1695 printw("You won the game. That is a feat to be proud of.\n");
1696 row
= originrow
+ 5;
1699 move(msgrow
, msgcol
);
1700 printw("You got %d card", cardsoff
);
1704 move(msgrow
, msgcol
);
1709 getcmd(row
, col
, "Play again (y or n)?");
1710 } while (srcpile
!= 'y' && srcpile
!= 'n');
1720 * procedure to clean up and exit
1723 cleanup(int dummy
__attribute__((__unused__
)))
1726 total
.thinktime
+= 1;
1728 updatebettinginfo();
1730 lseek(dbfd
, uid
* sizeof(struct betinfo
), SEEK_SET
);
1731 write(dbfd
, (char *)&total
, sizeof(total
));
1743 * Field an interrupt.
1746 askquit(int dummy
__attribute__((__unused__
)))
1748 move(msgrow
, msgcol
);
1749 printw("Really wish to quit? ");
1751 getcmd(moverow
, movecol
, "y or n?");
1752 } while (srcpile
!= 'y' && srcpile
!= 'n');
1756 signal(SIGINT
, askquit
);
1760 * Can you tell that this used to be a Pascal program?
1769 if (vec
[2] >= MAXLOAD
) {
1770 puts("The system load is too high. Try again later.");
1774 signal(SIGINT
, askquit
);
1775 signal(SIGHUP
, cleanup
);
1776 signal(SIGTERM
, cleanup
);