1 /*
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1980, 1993\n\
11 The Regents of the University of California. All rights reserved.\n";
12 #endif /* not lint */
13
14 #ifndef lint
15 static char sccsid[] = "@(#)canfield.c 8.1 (Berkeley) 05/31/93";
16 #endif /* not lint */
17
18 /*
19 * The canfield program
20 *
21 * Authors:
22 * Originally written: Steve Levine
23 * Converted to use curses and debugged: Steve Feldman
24 * Card counting: Kirk McKusick and Mikey Olson
25 * User interface cleanups: Eric Allman and Kirk McKusick
26 * Betting by Kirk McKusick
27 */
28
29 #include <sys/types.h>
30
31 #include <curses.h>
32 #include <ctype.h>
33 #include <signal.h>
34 #include <termios.h>
35
36 #include "pathnames.h"
37
38 #define decksize 52
39 #define originrow 0
40 #define origincol 0
41 #define basecol 1
42 #define boxcol 42
43 #define tboxrow 2
44 #define bboxrow 17
45 #define movecol 43
46 #define moverow 16
47 #define msgcol 43
48 #define msgrow 15
49 #define titlecol 30
50 #define titlerow 0
51 #define sidecol 1
52 #define ottlrow 6
53 #define foundcol 11
54 #define foundrow 3
55 #define stockcol 2
56 #define stockrow 8
57 #define fttlcol 10
58 #define fttlrow 1
59 #define taloncol 2
60 #define talonrow 13
61 #define tabrow 8
62 #define ctoprow 21
63 #define cbotrow 23
64 #define cinitcol 14
65 #define cheightcol 1
66 #define cwidthcol 4
67 #define handstatrow 21
68 #define handstatcol 7
69 #define talonstatrow 22
70 #define talonstatcol 7
71 #define stockstatrow 23
72 #define stockstatcol 7
73 #define Ace 1
74 #define Jack 11
75 #define Queen 12
76 #define King 13
77 #define atabcol 11
78 #define btabcol 18
79 #define ctabcol 25
80 #define dtabcol 32
81
82 #define spades 's'
83 #define clubs 'c'
84 #define hearts 'h'
85 #define diamonds 'd'
86 #define black 'b'
87 #define red 'r'
88
89 #define stk 1
90 #define tal 2
91 #define tab 3
92 #define INCRHAND(row, col) {\
93 row -= cheightcol;\
94 if (row < ctoprow) {\
95 row = cbotrow;\
96 col += cwidthcol;\
97 }\
98 }
99 #define DECRHAND(row, col) {\
100 row += cheightcol;\
101 if (row > cbotrow) {\
102 row = ctoprow;\
103 col -= cwidthcol;\
104 }\
105 }
106
107
108 struct cardtype {
109 char suit;
110 char color;
111 bool visible;
112 bool paid;
113 int rank;
114 struct cardtype *next;
115 };
116
117 #define NIL ((struct cardtype *) -1)
118
119 struct cardtype *deck[decksize];
120 struct cardtype cards[decksize];
121 struct cardtype *bottom[4], *found[4], *tableau[4];
122 struct cardtype *talon, *hand, *stock, *basecard;
123 int length[4];
124 int cardsoff, base, cinhand, taloncnt, stockcnt, timesthru;
125 char suitmap[4] = {spades, clubs, hearts, diamonds};
126 char colormap[4] = {black, black, red, red};
127 char pilemap[4] = {atabcol, btabcol, ctabcol, dtabcol};
128 char srcpile, destpile;
129 int mtforigin, tempbase;
130 int coldcol, cnewcol, coldrow, cnewrow;
131 bool errmsg, done;
132 bool mtfdone, Cflag = FALSE;
133 #define INSTRUCTIONBOX 1
134 #define BETTINGBOX 2
135 #define NOBOX 3
136 int status = INSTRUCTIONBOX;
137 int uid;
138
139 /*
140 * Basic betting costs
141 */
142 #define costofhand 13
143 #define costofinspection 13
144 #define costofgame 26
145 #define costofrunthroughhand 5
146 #define costofinformation 1
147 #define secondsperdollar 60
148 #define maxtimecharge 3
149 #define valuepercardup 5
150 /*
151 * Variables associated with betting
152 */
153 struct betinfo {
154 long hand; /* cost of dealing hand */
155 long inspection; /* cost of inspecting hand */
156 long game; /* cost of buying game */
157 long runs; /* cost of running through hands */
158 long information; /* cost of information */
159 long thinktime; /* cost of thinking time */
160 long wins; /* total winnings */
161 long worth; /* net worth after costs */
162 };
163 struct betinfo this, game, total;
164 bool startedgame = FALSE, infullgame = FALSE;
165 time_t acctstart;
166 int dbfd = -1;
167
168 /*
169 * The following procedures print the board onto the screen using the
170 * addressible cursor. The end of these procedures will also be
171 * separated from the rest of the program.
172 *
173 * procedure to set the move command box
174 */
movebox()175 movebox()
176 {
177 switch (status) {
178 case BETTINGBOX:
179 printtopbettingbox();
180 break;
181 case NOBOX:
182 clearabovemovebox();
183 break;
184 case INSTRUCTIONBOX:
185 printtopinstructions();
186 break;
187 }
188 move(moverow, boxcol);
189 printw("| |");
190 move(msgrow, boxcol);
191 printw("| |");
192 switch (status) {
193 case BETTINGBOX:
194 printbottombettingbox();
195 break;
196 case NOBOX:
197 clearbelowmovebox();
198 break;
199 case INSTRUCTIONBOX:
200 printbottominstructions();
201 break;
202 }
203 refresh();
204 }
205
206 /*
207 * print directions above move box
208 */
printtopinstructions()209 printtopinstructions()
210 {
211 move(tboxrow, boxcol);
212 printw("*----------------------------------*");
213 move(tboxrow + 1, boxcol);
214 printw("| MOVES |");
215 move(tboxrow + 2, boxcol);
216 printw("|s# = stock to tableau |");
217 move(tboxrow + 3, boxcol);
218 printw("|sf = stock to foundation |");
219 move(tboxrow + 4, boxcol);
220 printw("|t# = talon to tableau |");
221 move(tboxrow + 5, boxcol);
222 printw("|tf = talon to foundation |");
223 move(tboxrow + 6, boxcol);
224 printw("|## = tableau to tableau |");
225 move(tboxrow + 7, boxcol);
226 printw("|#f = tableau to foundation |");
227 move(tboxrow + 8, boxcol);
228 printw("|ht = hand to talon |");
229 move(tboxrow + 9, boxcol);
230 printw("|c = toggle card counting |");
231 move(tboxrow + 10, boxcol);
232 printw("|b = present betting information |");
233 move(tboxrow + 11, boxcol);
234 printw("|q = quit to end the game |");
235 move(tboxrow + 12, boxcol);
236 printw("|==================================|");
237 }
238
239 /*
240 * Print the betting box.
241 */
printtopbettingbox()242 printtopbettingbox()
243 {
244
245 move(tboxrow, boxcol);
246 printw("*----------------------------------*");
247 move(tboxrow + 1, boxcol);
248 printw("|Costs Hand Game Total |");
249 move(tboxrow + 2, boxcol);
250 printw("| Hands |");
251 move(tboxrow + 3, boxcol);
252 printw("| Inspections |");
253 move(tboxrow + 4, boxcol);
254 printw("| Games |");
255 move(tboxrow + 5, boxcol);
256 printw("| Runs |");
257 move(tboxrow + 6, boxcol);
258 printw("| Information |");
259 move(tboxrow + 7, boxcol);
260 printw("| Think time |");
261 move(tboxrow + 8, boxcol);
262 printw("|Total Costs |");
263 move(tboxrow + 9, boxcol);
264 printw("|Winnings |");
265 move(tboxrow + 10, boxcol);
266 printw("|Net Worth |");
267 move(tboxrow + 11, boxcol);
268 printw("|Return |");
269 move(tboxrow + 12, boxcol);
270 printw("|==================================|");
271 }
272
273 /*
274 * clear info above move box
275 */
clearabovemovebox()276 clearabovemovebox()
277 {
278 int i;
279
280 for (i = 0; i <= 11; i++) {
281 move(tboxrow + i, boxcol);
282 printw(" ");
283 }
284 move(tboxrow + 12, boxcol);
285 printw("*----------------------------------*");
286 }
287
288 /*
289 * print instructions below move box
290 */
printbottominstructions()291 printbottominstructions()
292 {
293 move(bboxrow, boxcol);
294 printw("|Replace # with the number of the |");
295 move(bboxrow + 1, boxcol);
296 printw("|tableau you want. |");
297 move(bboxrow + 2, boxcol);
298 printw("*----------------------------------*");
299 }
300
301 /*
302 * print betting information below move box
303 */
printbottombettingbox()304 printbottombettingbox()
305 {
306 move(bboxrow, boxcol);
307 printw("|x = toggle information box |");
308 move(bboxrow + 1, boxcol);
309 printw("|i = list playing instructions |");
310 move(bboxrow + 2, boxcol);
311 printw("*----------------------------------*");
312 }
313
314 /*
315 * clear info below move box
316 */
clearbelowmovebox()317 clearbelowmovebox()
318 {
319 int i;
320
321 move(bboxrow, boxcol);
322 printw("*----------------------------------*");
323 for (i = 1; i <= 2; i++) {
324 move(bboxrow + i, boxcol);
325 printw(" ");
326 }
327 }
328
329 /*
330 * procedure to put the board on the screen using addressable cursor
331 */
makeboard()332 makeboard()
333 {
334 clear();
335 refresh();
336 move(titlerow, titlecol);
337 printw("=-> CANFIELD <-=");
338 move(fttlrow, fttlcol);
339 printw("foundation");
340 move(foundrow - 1, fttlcol);
341 printw("=---= =---= =---= =---=");
342 move(foundrow, fttlcol);
343 printw("| | | | | | | |");
344 move(foundrow + 1, fttlcol);
345 printw("=---= =---= =---= =---=");
346 move(ottlrow, sidecol);
347 printw("stock tableau");
348 move(stockrow - 1, sidecol);
349 printw("=---=");
350 move(stockrow, sidecol);
351 printw("| |");
352 move(stockrow + 1, sidecol);
353 printw("=---=");
354 move(talonrow - 2, sidecol);
355 printw("talon");
356 move(talonrow - 1, sidecol);
357 printw("=---=");
358 move(talonrow, sidecol);
359 printw("| |");
360 move(talonrow + 1, sidecol);
361 printw("=---=");
362 move(tabrow - 1, atabcol);
363 printw("-1- -2- -3- -4-");
364 movebox();
365 }
366
367 /*
368 * clean up the board for another game
369 */
cleanupboard()370 cleanupboard()
371 {
372 int cnt, row, col;
373 struct cardtype *ptr;
374
375 if (Cflag) {
376 clearstat();
377 for(ptr = stock, row = stockrow;
378 ptr != NIL;
379 ptr = ptr->next, row++) {
380 move(row, sidecol);
381 printw(" ");
382 }
383 move(row, sidecol);
384 printw(" ");
385 move(stockrow + 1, sidecol);
386 printw("=---=");
387 move(talonrow - 2, sidecol);
388 printw("talon");
389 move(talonrow - 1, sidecol);
390 printw("=---=");
391 move(talonrow + 1, sidecol);
392 printw("=---=");
393 }
394 move(stockrow, sidecol);
395 printw("| |");
396 move(talonrow, sidecol);
397 printw("| |");
398 move(foundrow, fttlcol);
399 printw("| | | | | | | |");
400 for (cnt = 0; cnt < 4; cnt++) {
401 switch(cnt) {
402 case 0:
403 col = atabcol;
404 break;
405 case 1:
406 col = btabcol;
407 break;
408 case 2:
409 col = ctabcol;
410 break;
411 case 3:
412 col = dtabcol;
413 break;
414 }
415 for(ptr = tableau[cnt], row = tabrow;
416 ptr != NIL;
417 ptr = ptr->next, row++)
418 removecard(col, row);
419 }
420 }
421
422 /*
423 * procedure to create a deck of cards
424 */
425 initdeck(deck)
426 struct cardtype *deck[];
427 {
428 int i;
429 int scnt;
430 char s;
431 int r;
432
433 i = 0;
434 for (scnt=0; scnt<4; scnt++) {
435 s = suitmap[scnt];
436 for (r=Ace; r<=King; r++) {
437 deck[i] = &cards[i];
438 cards[i].rank = r;
439 cards[i].suit = s;
440 cards[i].color = colormap[scnt];
441 cards[i].next = NIL;
442 i++;
443 }
444 }
445 }
446
447 /*
448 * procedure to shuffle the deck
449 */
450 shuffle(deck)
451 struct cardtype *deck[];
452 {
453 int i,j;
454 struct cardtype *temp;
455
456 for (i=0; i<decksize; i++) {
457 deck[i]->visible = FALSE;
458 deck[i]->paid = FALSE;
459 }
460 for (i = decksize-1; i>=0; i--) {
461 j = random() % decksize;
462 if (i != j) {
463 temp = deck[i];
464 deck[i] = deck[j];
465 deck[j] = temp;
466 }
467 }
468 }
469
470 /*
471 * procedure to remove the card from the board
472 */
removecard(a,b)473 removecard(a, b)
474 {
475 move(b, a);
476 printw(" ");
477 }
478
479 /*
480 * procedure to print the cards on the board
481 */
482 printrank(a, b, cp, inverse)
483 struct cardtype *cp;
484 bool inverse;
485 {
486 move(b, a);
487 if (cp->rank != 10)
488 addch(' ');
489 if (inverse)
490 standout();
491 switch (cp->rank) {
492 case 2: case 3: case 4: case 5: case 6: case 7:
493 case 8: case 9: case 10:
494 printw("%d", cp->rank);
495 break;
496 case Ace:
497 addch('A');
498 break;
499 case Jack:
500 addch('J');
501 break;
502 case Queen:
503 addch('Q');
504 break;
505 case King:
506 addch('K');
507 }
508 if (inverse)
509 standend();
510 }
511
512 /*
513 * procedure to print out a card
514 */
printcard(a,b,cp)515 printcard(a, b, cp)
516 int a,b;
517 struct cardtype *cp;
518 {
519 if (cp == NIL)
520 removecard(a, b);
521 else if (cp->visible == FALSE) {
522 move(b, a);
523 printw(" ? ");
524 } else {
525 bool inverse = (cp->suit == 'd' || cp->suit == 'h');
526
527 printrank(a, b, cp, inverse);
528 if (inverse)
529 standout();
530 addch(cp->suit);
531 if (inverse)
532 standend();
533 }
534 }
535
536 /*
537 * procedure to move the top card from one location to the top
538 * of another location. The pointers always point to the top
539 * of the piles.
540 */
541 transit(source, dest)
542 struct cardtype **source, **dest;
543 {
544 struct cardtype *temp;
545
546 temp = *source;
547 *source = (*source)->next;
548 temp->next = *dest;
549 *dest = temp;
550 }
551
552 /*
553 * Procedure to set the cards on the foundation base when available.
554 * Note that it is only called on a foundation pile at the beginning of
555 * the game, so the pile will have exactly one card in it.
556 */
557 fndbase(cp, column, row)
558 struct cardtype **cp;
559 {
560 bool nomore;
561
562 if (*cp != NIL)
563 do {
564 if ((*cp)->rank == basecard->rank) {
565 base++;
566 printcard(pilemap[base], foundrow, *cp);
567 if (*cp == tableau[0])
568 length[0] = length[0] - 1;
569 if (*cp == tableau[1])
570 length[1] = length[1] - 1;
571 if (*cp == tableau[2])
572 length[2] = length[2] - 1;
573 if (*cp == tableau[3])
574 length[3] = length[3] - 1;
575 transit(cp, &found[base]);
576 if (cp == &talon)
577 usedtalon();
578 if (cp == &stock)
579 usedstock();
580 if (*cp != NIL) {
581 printcard(column, row, *cp);
582 nomore = FALSE;
583 } else {
584 removecard(column, row);
585 nomore = TRUE;
586 }
587 cardsoff++;
588 if (infullgame) {
589 this.wins += valuepercardup;
590 game.wins += valuepercardup;
591 total.wins += valuepercardup;
592 }
593 } else
594 nomore = TRUE;
595 } while (nomore == FALSE);
596 }
597
598 /*
599 * procedure to initialize the things necessary for the game
600 */
initgame()601 initgame()
602 {
603 register i;
604
605 for (i=0; i<18; i++) {
606 deck[i]->visible = TRUE;
607 deck[i]->paid = TRUE;
608 }
609 stockcnt = 13;
610 stock = deck[12];
611 for (i=12; i>=1; i--)
612 deck[i]->next = deck[i - 1];
613 deck[0]->next = NIL;
614 found[0] = deck[13];
615 deck[13]->next = NIL;
616 for (i=1; i<4; i++)
617 found[i] = NIL;
618 basecard = found[0];
619 for (i=14; i<18; i++) {
620 tableau[i - 14] = deck[i];
621 deck[i]->next = NIL;
622 }
623 for (i=0; i<4; i++) {
624 bottom[i] = tableau[i];
625 length[i] = tabrow;
626 }
627 hand = deck[18];
628 for (i=18; i<decksize-1; i++)
629 deck[i]->next = deck[i + 1];
630 deck[decksize-1]->next = NIL;
631 talon = NIL;
632 base = 0;
633 cinhand = 34;
634 taloncnt = 0;
635 timesthru = 0;
636 cardsoff = 1;
637 coldrow = ctoprow;
638 coldcol = cinitcol;
639 cnewrow = ctoprow;
640 cnewcol = cinitcol + cwidthcol;
641 }
642
643 /*
644 * procedure to print the beginning cards and to start each game
645 */
startgame()646 startgame()
647 {
648 register int j;
649
650 shuffle(deck);
651 initgame();
652 this.hand = costofhand;
653 game.hand += costofhand;
654 total.hand += costofhand;
655 this.inspection = 0;
656 this.game = 0;
657 this.runs = 0;
658 this.information = 0;
659 this.wins = 0;
660 this.thinktime = 0;
661 infullgame = FALSE;
662 startedgame = FALSE;
663 printcard(foundcol, foundrow, found[0]);
664 printcard(stockcol, stockrow, stock);
665 printcard(atabcol, tabrow, tableau[0]);
666 printcard(btabcol, tabrow, tableau[1]);
667 printcard(ctabcol, tabrow, tableau[2]);
668 printcard(dtabcol, tabrow, tableau[3]);
669 printcard(taloncol, talonrow, talon);
670 move(foundrow - 2, basecol);
671 printw("Base");
672 move(foundrow - 1, basecol);
673 printw("Rank");
674 printrank(basecol, foundrow, found[0], 0);
675 for (j=0; j<=3; j++)
676 fndbase(&tableau[j], pilemap[j], tabrow);
677 fndbase(&stock, stockcol, stockrow);
678 showstat(); /* show card counting info to cheaters */
679 movetotalon();
680 updatebettinginfo();
681 }
682
683 /*
684 * procedure to clear the message printed from an error
685 */
clearmsg()686 clearmsg()
687 {
688 int i;
689
690 if (errmsg == TRUE) {
691 errmsg = FALSE;
692 move(msgrow, msgcol);
693 for (i=0; i<25; i++)
694 addch(' ');
695 refresh();
696 }
697 }
698
699 /*
700 * procedure to print an error message if the move is not listed
701 */
dumberror()702 dumberror()
703 {
704 errmsg = TRUE;
705 move(msgrow, msgcol);
706 printw("Not a proper move ");
707 }
708
709 /*
710 * procedure to print an error message if the move is not possible
711 */
destinerror()712 destinerror()
713 {
714 errmsg = TRUE;
715 move(msgrow, msgcol);
716 printw("Error: Can't move there");
717 }
718
719 /*
720 * function to see if the source has cards in it
721 */
722 bool
notempty(cp)723 notempty(cp)
724 struct cardtype *cp;
725 {
726 if (cp == NIL) {
727 errmsg = TRUE;
728 move(msgrow, msgcol);
729 printw("Error: no cards to move");
730 return (FALSE);
731 } else
732 return (TRUE);
733 }
734
735 /*
736 * function to see if the rank of one card is less than another
737 */
738 bool
ranklower(cp1,cp2)739 ranklower(cp1, cp2)
740 struct cardtype *cp1, *cp2;
741 {
742 if (cp2->rank == Ace)
743 if (cp1->rank == King)
744 return (TRUE);
745 else
746 return (FALSE);
747 else if (cp1->rank + 1 == cp2->rank)
748 return (TRUE);
749 else
750 return (FALSE);
751 }
752
753 /*
754 * function to check the cardcolor for moving to a tableau
755 */
756 bool
diffcolor(cp1,cp2)757 diffcolor(cp1, cp2)
758 struct cardtype *cp1, *cp2;
759 {
760 if (cp1->color == cp2->color)
761 return (FALSE);
762 else
763 return (TRUE);
764 }
765
766 /*
767 * function to see if the card can move to the tableau
768 */
769 bool
tabok(cp,des)770 tabok(cp, des)
771 struct cardtype *cp;
772 {
773 if ((cp == stock) && (tableau[des] == NIL))
774 return (TRUE);
775 else if (tableau[des] == NIL)
776 if (stock == NIL &&
777 cp != bottom[0] && cp != bottom[1] &&
778 cp != bottom[2] && cp != bottom[3])
779 return (TRUE);
780 else
781 return (FALSE);
782 else if (ranklower(cp, tableau[des]) && diffcolor(cp, tableau[des]))
783 return (TRUE);
784 else
785 return (FALSE);
786 }
787
788 /*
789 * procedure to turn the cards onto the talon from the deck
790 */
movetotalon()791 movetotalon()
792 {
793 int i, fin;
794
795 if (cinhand <= 3 && cinhand > 0) {
796 move(msgrow, msgcol);
797 printw("Hand is now empty ");
798 }
799 if (cinhand >= 3)
800 fin = 3;
801 else if (cinhand > 0)
802 fin = cinhand;
803 else if (talon != NIL) {
804 timesthru++;
805 errmsg = TRUE;
806 move(msgrow, msgcol);
807 if (timesthru != 4) {
808 printw("Talon is now the new hand");
809 this.runs += costofrunthroughhand;
810 game.runs += costofrunthroughhand;
811 total.runs += costofrunthroughhand;
812 while (talon != NIL) {
813 transit(&talon, &hand);
814 cinhand++;
815 }
816 if (cinhand >= 3)
817 fin = 3;
818 else
819 fin = cinhand;
820 taloncnt = 0;
821 coldrow = ctoprow;
822 coldcol = cinitcol;
823 cnewrow = ctoprow;
824 cnewcol = cinitcol + cwidthcol;
825 clearstat();
826 showstat();
827 } else {
828 fin = 0;
829 done = TRUE;
830 printw("I believe you have lost");
831 refresh();
832 sleep(5);
833 }
834 } else {
835 errmsg = TRUE;
836 move(msgrow, msgcol);
837 printw("Talon and hand are empty");
838 fin = 0;
839 }
840 for (i=0; i<fin; i++) {
841 transit(&hand, &talon);
842 INCRHAND(cnewrow, cnewcol);
843 INCRHAND(coldrow, coldcol);
844 removecard(cnewcol, cnewrow);
845 if (i == fin - 1)
846 talon->visible = TRUE;
847 if (Cflag) {
848 if (talon->paid == FALSE && talon->visible == TRUE) {
849 this.information += costofinformation;
850 game.information += costofinformation;
851 total.information += costofinformation;
852 talon->paid = TRUE;
853 }
854 printcard(coldcol, coldrow, talon);
855 }
856 }
857 if (fin != 0) {
858 printcard(taloncol, talonrow, talon);
859 cinhand -= fin;
860 taloncnt += fin;
861 if (Cflag) {
862 move(handstatrow, handstatcol);
863 printw("%3d", cinhand);
864 move(talonstatrow, talonstatcol);
865 printw("%3d", taloncnt);
866 }
867 fndbase(&talon, taloncol, talonrow);
868 }
869 }
870
871
872 /*
873 * procedure to print card counting info on screen
874 */
showstat()875 showstat()
876 {
877 int row, col;
878 register struct cardtype *ptr;
879
880 if (!Cflag)
881 return;
882 move(talonstatrow, talonstatcol - 7);
883 printw("Talon: %3d", taloncnt);
884 move(handstatrow, handstatcol - 7);
885 printw("Hand: %3d", cinhand);
886 move(stockstatrow, stockstatcol - 7);
887 printw("Stock: %3d", stockcnt);
888 for ( row = coldrow, col = coldcol, ptr = talon;
889 ptr != NIL;
890 ptr = ptr->next ) {
891 if (ptr->paid == FALSE && ptr->visible == TRUE) {
892 ptr->paid = TRUE;
893 this.information += costofinformation;
894 game.information += costofinformation;
895 total.information += costofinformation;
896 }
897 printcard(col, row, ptr);
898 DECRHAND(row, col);
899 }
900 for ( row = cnewrow, col = cnewcol, ptr = hand;
901 ptr != NIL;
902 ptr = ptr->next ) {
903 if (ptr->paid == FALSE && ptr->visible == TRUE) {
904 ptr->paid = TRUE;
905 this.information += costofinformation;
906 game.information += costofinformation;
907 total.information += costofinformation;
908 }
909 INCRHAND(row, col);
910 printcard(col, row, ptr);
911 }
912 }
913
914 /*
915 * procedure to clear card counting info from screen
916 */
clearstat()917 clearstat()
918 {
919 int row;
920
921 move(talonstatrow, talonstatcol - 7);
922 printw(" ");
923 move(handstatrow, handstatcol - 7);
924 printw(" ");
925 move(stockstatrow, stockstatcol - 7);
926 printw(" ");
927 for ( row = ctoprow ; row <= cbotrow ; row++ ) {
928 move(row, cinitcol);
929 printw("%56s", " ");
930 }
931 }
932
933 /*
934 * procedure to update card counting base
935 */
usedtalon()936 usedtalon()
937 {
938 removecard(coldcol, coldrow);
939 DECRHAND(coldrow, coldcol);
940 if (talon != NIL && (talon->visible == FALSE)) {
941 talon->visible = TRUE;
942 if (Cflag) {
943 this.information += costofinformation;
944 game.information += costofinformation;
945 total.information += costofinformation;
946 talon->paid = TRUE;
947 printcard(coldcol, coldrow, talon);
948 }
949 }
950 taloncnt--;
951 if (Cflag) {
952 move(talonstatrow, talonstatcol);
953 printw("%3d", taloncnt);
954 }
955 }
956
957 /*
958 * procedure to update stock card counting base
959 */
usedstock()960 usedstock()
961 {
962 stockcnt--;
963 if (Cflag) {
964 move(stockstatrow, stockstatcol);
965 printw("%3d", stockcnt);
966 }
967 }
968
969 /*
970 * let 'em know how they lost!
971 */
showcards()972 showcards()
973 {
974 register struct cardtype *ptr;
975 int row;
976
977 if (!Cflag || cardsoff == 52)
978 return;
979 for (ptr = talon; ptr != NIL; ptr = ptr->next) {
980 ptr->visible = TRUE;
981 ptr->paid = TRUE;
982 }
983 for (ptr = hand; ptr != NIL; ptr = ptr->next) {
984 ptr->visible = TRUE;
985 ptr->paid = TRUE;
986 }
987 showstat();
988 move(stockrow + 1, sidecol);
989 printw(" ");
990 move(talonrow - 2, sidecol);
991 printw(" ");
992 move(talonrow - 1, sidecol);
993 printw(" ");
994 move(talonrow, sidecol);
995 printw(" ");
996 move(talonrow + 1, sidecol);
997 printw(" ");
998 for (ptr = stock, row = stockrow; ptr != NIL; ptr = ptr->next, row++) {
999 move(row, stockcol - 1);
1000 printw("| |");
1001 printcard(stockcol, row, ptr);
1002 }
1003 if (stock == NIL) {
1004 move(row, stockcol - 1);
1005 printw("| |");
1006 row++;
1007 }
1008 move(handstatrow, handstatcol - 7);
1009 printw(" ");
1010 move(row, stockcol - 1);
1011 printw("=---=");
1012 if ( cardsoff == 52 )
1013 getcmd(moverow, movecol, "Hit return to exit");
1014 }
1015
1016 /*
1017 * procedure to update the betting values
1018 */
updatebettinginfo()1019 updatebettinginfo()
1020 {
1021 long thiscosts, gamecosts, totalcosts;
1022 double thisreturn, gamereturn, totalreturn;
1023 time_t now;
1024 register long dollars;
1025
1026 time(&now);
1027 dollars = (now - acctstart) / secondsperdollar;
1028 if (dollars > 0) {
1029 acctstart += dollars * secondsperdollar;
1030 if (dollars > maxtimecharge)
1031 dollars = maxtimecharge;
1032 this.thinktime += dollars;
1033 game.thinktime += dollars;
1034 total.thinktime += dollars;
1035 }
1036 thiscosts = this.hand + this.inspection + this.game +
1037 this.runs + this.information + this.thinktime;
1038 gamecosts = game.hand + game.inspection + game.game +
1039 game.runs + game.information + game.thinktime;
1040 totalcosts = total.hand + total.inspection + total.game +
1041 total.runs + total.information + total.thinktime;
1042 this.worth = this.wins - thiscosts;
1043 game.worth = game.wins - gamecosts;
1044 total.worth = total.wins - totalcosts;
1045 thisreturn = ((double)this.wins / (double)thiscosts - 1.0) * 100.0;
1046 gamereturn = ((double)game.wins / (double)gamecosts - 1.0) * 100.0;
1047 totalreturn = ((double)total.wins / (double)totalcosts - 1.0) * 100.0;
1048 if (status != BETTINGBOX)
1049 return;
1050 move(tboxrow + 2, boxcol + 13);
1051 printw("%4d%8d%9d", this.hand, game.hand, total.hand);
1052 move(tboxrow + 3, boxcol + 13);
1053 printw("%4d%8d%9d", this.inspection, game.inspection, total.inspection);
1054 move(tboxrow + 4, boxcol + 13);
1055 printw("%4d%8d%9d", this.game, game.game, total.game);
1056 move(tboxrow + 5, boxcol + 13);
1057 printw("%4d%8d%9d", this.runs, game.runs, total.runs);
1058 move(tboxrow + 6, boxcol + 13);
1059 printw("%4d%8d%9d", this.information, game.information,
1060 total.information);
1061 move(tboxrow + 7, boxcol + 13);
1062 printw("%4d%8d%9d", this.thinktime, game.thinktime, total.thinktime);
1063 move(tboxrow + 8, boxcol + 13);
1064 printw("%4d%8d%9d", thiscosts, gamecosts, totalcosts);
1065 move(tboxrow + 9, boxcol + 13);
1066 printw("%4d%8d%9d", this.wins, game.wins, total.wins);
1067 move(tboxrow + 10, boxcol + 13);
1068 printw("%4d%8d%9d", this.worth, game.worth, total.worth);
1069 move(tboxrow + 11, boxcol + 13);
1070 printw("%4.0f%%%7.1f%%%8.1f%%", thisreturn, gamereturn, totalreturn);
1071 }
1072
1073 /*
1074 * procedure to move a card from the stock or talon to the tableau
1075 */
1076 simpletableau(cp, des)
1077 struct cardtype **cp;
1078 {
1079 int origin;
1080
1081 if (notempty(*cp)) {
1082 if (tabok(*cp, des)) {
1083 if (*cp == stock)
1084 origin = stk;
1085 else
1086 origin = tal;
1087 if (tableau[des] == NIL)
1088 bottom[des] = *cp;
1089 transit(cp, &tableau[des]);
1090 length[des]++;
1091 printcard(pilemap[des], length[des], tableau[des]);
1092 timesthru = 0;
1093 if (origin == stk) {
1094 usedstock();
1095 printcard(stockcol, stockrow, stock);
1096 } else {
1097 usedtalon();
1098 printcard(taloncol, talonrow, talon);
1099 }
1100 } else
1101 destinerror();
1102 }
1103 }
1104
1105 /*
1106 * print the tableau
1107 */
tabprint(sour,des)1108 tabprint(sour, des)
1109 {
1110 int dlength, slength, i;
1111 struct cardtype *tempcard;
1112
1113 for (i=tabrow; i<=length[sour]; i++)
1114 removecard(pilemap[sour], i);
1115 dlength = length[des] + 1;
1116 slength = length[sour];
1117 if (slength == tabrow)
1118 printcard(pilemap[des], dlength, tableau[sour]);
1119 else
1120 while (slength != tabrow - 1) {
1121 tempcard = tableau[sour];
1122 for (i=1; i<=slength-tabrow; i++)
1123 tempcard = tempcard->next;
1124 printcard(pilemap[des], dlength, tempcard);
1125 slength--;
1126 dlength++;
1127 }
1128 }
1129
1130 /*
1131 * procedure to move from the tableau to the tableau
1132 */
tabtotab(sour,des)1133 tabtotab(sour, des)
1134 register int sour, des;
1135 {
1136 struct cardtype *temp;
1137
1138 if (notempty(tableau[sour])) {
1139 if (tabok(bottom[sour], des)) {
1140 tabprint(sour, des);
1141 temp = bottom[sour];
1142 bottom[sour] = NIL;
1143 if (bottom[des] == NIL)
1144 bottom[des] = temp;
1145 temp->next = tableau[des];
1146 tableau[des] = tableau[sour];
1147 tableau[sour] = NIL;
1148 length[des] = length[des] + (length[sour] - (tabrow - 1));
1149 length[sour] = tabrow - 1;
1150 timesthru = 0;
1151 } else
1152 destinerror();
1153 }
1154 }
1155
1156 /*
1157 * functions to see if the card can go onto the foundation
1158 */
1159 bool
rankhigher(cp,let)1160 rankhigher(cp, let)
1161 struct cardtype *cp;
1162 {
1163 if (found[let]->rank == King)
1164 if (cp->rank == Ace)
1165 return(TRUE);
1166 else
1167 return(FALSE);
1168 else if (cp->rank - 1 == found[let]->rank)
1169 return(TRUE);
1170 else
1171 return(FALSE);
1172 }
1173
1174 /*
1175 * function to determine if two cards are the same suit
1176 */
1177 samesuit(cp, let)
1178 struct cardtype *cp;
1179 {
1180 if (cp->suit == found[let]->suit)
1181 return (TRUE);
1182 else
1183 return (FALSE);
1184 }
1185
1186 /*
1187 * procedure to move a card to the correct foundation pile
1188 */
1189 movetofound(cp, source)
1190 struct cardtype **cp;
1191 {
1192 tempbase = 0;
1193 mtfdone = FALSE;
1194 if (notempty(*cp)) {
1195 do {
1196 if (found[tempbase] != NIL)
1197 if (rankhigher(*cp, tempbase)
1198 && samesuit(*cp, tempbase)) {
1199 if (*cp == stock)
1200 mtforigin = stk;
1201 else if (*cp == talon)
1202 mtforigin = tal;
1203 else
1204 mtforigin = tab;
1205 transit(cp, &found[tempbase]);
1206 printcard(pilemap[tempbase],
1207 foundrow, found[tempbase]);
1208 timesthru = 0;
1209 if (mtforigin == stk) {
1210 usedstock();
1211 printcard(stockcol, stockrow, stock);
1212 } else if (mtforigin == tal) {
1213 usedtalon();
1214 printcard(taloncol, talonrow, talon);
1215 } else {
1216 removecard(pilemap[source], length[source]);
1217 length[source]--;
1218 }
1219 cardsoff++;
1220 if (infullgame) {
1221 this.wins += valuepercardup;
1222 game.wins += valuepercardup;
1223 total.wins += valuepercardup;
1224 }
1225 mtfdone = TRUE;
1226 } else
1227 tempbase++;
1228 else
1229 tempbase++;
1230 } while ((tempbase != 4) && !mtfdone);
1231 if (!mtfdone)
1232 destinerror();
1233 }
1234 }
1235
1236 /*
1237 * procedure to get a command
1238 */
getcmd(row,col,cp)1239 getcmd(row, col, cp)
1240 int row, col;
1241 char *cp;
1242 {
1243 char cmd[2], ch;
1244 int i;
1245
1246 i = 0;
1247 move(row, col);
1248 printw("%-24s", cp);
1249 col += 1 + strlen(cp);
1250 move(row, col);
1251 refresh();
1252 do {
1253 ch = getch() & 0177;
1254 if (ch >= 'A' && ch <= 'Z')
1255 ch += ('a' - 'A');
1256 if (ch == '\f') {
1257 wrefresh(curscr);
1258 refresh();
1259 } else if (i >= 2 && ch != erasechar() && ch != killchar()) {
1260 if (ch != '\n' && ch != '\r' && ch != ' ')
1261 write(1, "\007", 1);
1262 } else if (ch == erasechar() && i > 0) {
1263 printw("\b \b");
1264 refresh();
1265 i--;
1266 } else if (ch == killchar() && i > 0) {
1267 while (i > 0) {
1268 printw("\b \b");
1269 i--;
1270 }
1271 refresh();
1272 } else if (ch == '\032') { /* Control-Z */
1273 suspend();
1274 move(row, col + i);
1275 refresh();
1276 } else if (isprint(ch)) {
1277 cmd[i++] = ch;
1278 addch(ch);
1279 refresh();
1280 }
1281 } while (ch != '\n' && ch != '\r' && ch != ' ');
1282 srcpile = cmd[0];
1283 destpile = cmd[1];
1284 }
1285
1286 /*
1287 * Suspend the game (shell escape if no process control on system)
1288 */
suspend()1289 suspend()
1290 {
1291 #ifndef SIGTSTP
1292 char *sh;
1293 #endif
1294
1295 updatebettinginfo();
1296 move(21, 0);
1297 refresh();
1298 if (dbfd != -1) {
1299 lseek(dbfd, uid * sizeof(struct betinfo), 0);
1300 write(dbfd, (char *)&total, sizeof(total));
1301 }
1302 kill(getpid(), SIGTSTP);
1303 raw();
1304 noecho();
1305 }
1306
1307 /*
1308 * procedure to evaluate and make the specific moves
1309 */
movecard()1310 movecard()
1311 {
1312 int source, dest;
1313 char osrcpile, odestpile;
1314
1315 done = FALSE;
1316 errmsg = FALSE;
1317 do {
1318 if (talon == NIL && hand != NIL)
1319 movetotalon();
1320 if (cardsoff == 52) {
1321 refresh();
1322 srcpile = 'q';
1323 } else if (!startedgame) {
1324 move(msgrow, msgcol);
1325 errmsg = TRUE;
1326 switch (34 - taloncnt - cinhand) {
1327 default:
1328 errmsg = FALSE;
1329 break;
1330 case 1:
1331 printw("One card used from talon ");
1332 break;
1333 case 2:
1334 printw("Two cards used from talon ");
1335 break;
1336 case 3:
1337 printw(">3< cards used from talon ");
1338 break;
1339 }
1340 getcmd(moverow, movecol, "Move:");
1341 } else
1342 getcmd(moverow, movecol, "Move:");
1343 clearmsg();
1344 if (srcpile >= '1' && srcpile <= '4')
1345 source = (int) (srcpile - '1');
1346 if (destpile >= '1' && destpile <= '4')
1347 dest = (int) (destpile - '1');
1348 if (!startedgame &&
1349 (srcpile == 't' || srcpile == 's' || srcpile == 'h' ||
1350 srcpile == '1' || srcpile == '2' || srcpile == '3' ||
1351 srcpile == '4')) {
1352 startedgame = TRUE;
1353 osrcpile = srcpile;
1354 odestpile = destpile;
1355 if (status != BETTINGBOX)
1356 srcpile = 'y';
1357 else do {
1358 getcmd(moverow, movecol, "Inspect game?");
1359 } while (srcpile != 'y' && srcpile != 'n');
1360 if (srcpile == 'n') {
1361 srcpile = 'q';
1362 } else {
1363 this.inspection += costofinspection;
1364 game.inspection += costofinspection;
1365 total.inspection += costofinspection;
1366 srcpile = osrcpile;
1367 destpile = odestpile;
1368 }
1369 }
1370 switch (srcpile) {
1371 case 't':
1372 if (destpile == 'f' || destpile == 'F')
1373 movetofound(&talon, source);
1374 else if (destpile >= '1' && destpile <= '4')
1375 simpletableau(&talon, dest);
1376 else
1377 dumberror();
1378 break;
1379 case 's':
1380 if (destpile == 'f' || destpile == 'F')
1381 movetofound(&stock, source);
1382 else if (destpile >= '1' && destpile <= '4')
1383 simpletableau(&stock, dest);
1384 else dumberror();
1385 break;
1386 case 'h':
1387 if (destpile != 't' && destpile != 'T') {
1388 dumberror();
1389 break;
1390 }
1391 if (infullgame) {
1392 movetotalon();
1393 break;
1394 }
1395 if (status == BETTINGBOX) {
1396 do {
1397 getcmd(moverow, movecol,
1398 "Buy game?");
1399 } while (srcpile != 'y' &&
1400 srcpile != 'n');
1401 if (srcpile == 'n') {
1402 showcards();
1403 done = TRUE;
1404 break;
1405 }
1406 }
1407 infullgame = TRUE;
1408 this.wins += valuepercardup * cardsoff;
1409 game.wins += valuepercardup * cardsoff;
1410 total.wins += valuepercardup * cardsoff;
1411 this.game += costofgame;
1412 game.game += costofgame;
1413 total.game += costofgame;
1414 movetotalon();
1415 break;
1416 case 'q':
1417 showcards();
1418 done = TRUE;
1419 break;
1420 case 'b':
1421 printtopbettingbox();
1422 printbottombettingbox();
1423 status = BETTINGBOX;
1424 break;
1425 case 'x':
1426 clearabovemovebox();
1427 clearbelowmovebox();
1428 status = NOBOX;
1429 break;
1430 case 'i':
1431 printtopinstructions();
1432 printbottominstructions();
1433 status = INSTRUCTIONBOX;
1434 break;
1435 case 'c':
1436 Cflag = !Cflag;
1437 if (Cflag)
1438 showstat();
1439 else
1440 clearstat();
1441 break;
1442 case '1': case '2': case '3': case '4':
1443 if (destpile == 'f' || destpile == 'F')
1444 movetofound(&tableau[source], source);
1445 else if (destpile >= '1' && destpile <= '4')
1446 tabtotab(source, dest);
1447 else dumberror();
1448 break;
1449 default:
1450 dumberror();
1451 }
1452 fndbase(&stock, stockcol, stockrow);
1453 fndbase(&talon, taloncol, talonrow);
1454 updatebettinginfo();
1455 } while (!done);
1456 }
1457
1458 char *basicinstructions[] = {
1459 "Here are brief instuctions to the game of Canfield:\n\n",
1460 " If you have never played solitaire before, it is recom-\n",
1461 "mended that you consult a solitaire instruction book. In\n",
1462 "Canfield, tableau cards may be built on each other downward\n",
1463 "in alternate colors. An entire pile must be moved as a unit\n",
1464 "in building. Top cards of the piles are available to be able\n",
1465 "to be played on foundations, but never into empty spaces.\n\n",
1466 " Spaces must be filled from the stock. The top card of\n",
1467 "the stock also is available to be played on foundations or\n",
1468 "built on tableau piles. After the stock is exhausted, ta-\n",
1469 "bleau spaces may be filled from the talon and the player may\n",
1470 "keep them open until he wishes to use them.\n\n",
1471 " Cards are dealt from the hand to the talon by threes\n",
1472 "and this repeats until there are no more cards in the hand\n",
1473 "or the player quits. To have cards dealt onto the talon the\n",
1474 "player types 'ht' for his move. Foundation base cards are\n",
1475 "also automatically moved to the foundation when they become\n",
1476 "available.\n\n",
1477 "push any key when you are finished: ",
1478 0 };
1479
1480 char *bettinginstructions[] = {
1481 " The rules for betting are somewhat less strict than\n",
1482 "those used in the official version of the game. The initial\n",
1483 "deal costs $13. You may quit at this point or inspect the\n",
1484 "game. Inspection costs $13 and allows you to make as many\n",
1485 "moves as is possible without moving any cards from your hand\n",
1486 "to the talon. (the initial deal places three cards on the\n",
1487 "talon; if all these cards are used, three more are made\n",
1488 "available) Finally, if the game seems interesting, you must\n",
1489 "pay the final installment of $26. At this point you are\n",
1490 "credited at the rate of $5 for each card on the foundation;\n",
1491 "as the game progresses you are credited with $5 for each\n",
1492 "card that is moved to the foundation. Each run through the\n",
1493 "hand after the first costs $5. The card counting feature\n",
1494 "costs $1 for each unknown card that is identified. If the\n",
1495 "information is toggled on, you are only charged for cards\n",
1496 "that became visible since it was last turned on. Thus the\n",
1497 "maximum cost of information is $34. Playing time is charged\n",
1498 "at a rate of $1 per minute.\n\n",
1499 "push any key when you are finished: ",
1500 0 };
1501
1502 /*
1503 * procedure to printout instructions
1504 */
instruct()1505 instruct()
1506 {
1507 register char **cp;
1508
1509 move(originrow, origincol);
1510 printw("This is the game of solitaire called Canfield. Do\n");
1511 printw("you want instructions for the game?");
1512 do {
1513 getcmd(originrow + 3, origincol, "y or n?");
1514 } while (srcpile != 'y' && srcpile != 'n');
1515 if (srcpile == 'n')
1516 return;
1517 clear();
1518 for (cp = basicinstructions; *cp != 0; cp++)
1519 printw(*cp);
1520 refresh();
1521 getch();
1522 clear();
1523 move(originrow, origincol);
1524 printw("Do you want instructions for betting?");
1525 do {
1526 getcmd(originrow + 2, origincol, "y or n?");
1527 } while (srcpile != 'y' && srcpile != 'n');
1528 if (srcpile == 'n')
1529 return;
1530 clear();
1531 for (cp = bettinginstructions; *cp != 0; cp++)
1532 printw(*cp);
1533 refresh();
1534 getch();
1535 }
1536
1537 /*
1538 * procedure to initialize the game
1539 */
initall()1540 initall()
1541 {
1542 int i;
1543
1544 srandom(getpid());
1545 time(&acctstart);
1546 initdeck(deck);
1547 uid = getuid();
1548 if (uid < 0)
1549 uid = 0;
1550 dbfd = open(_PATH_SCORE, 2);
1551 if (dbfd < 0)
1552 return;
1553 i = lseek(dbfd, uid * sizeof(struct betinfo), 0);
1554 if (i < 0) {
1555 close(dbfd);
1556 dbfd = -1;
1557 return;
1558 }
1559 i = read(dbfd, (char *)&total, sizeof(total));
1560 if (i < 0) {
1561 close(dbfd);
1562 dbfd = -1;
1563 return;
1564 }
1565 }
1566
1567 /*
1568 * procedure to end the game
1569 */
1570 bool
finish()1571 finish()
1572 {
1573 int row, col;
1574
1575 if (cardsoff == 52) {
1576 getcmd(moverow, movecol, "Hit return to exit");
1577 clear();
1578 refresh();
1579 move(originrow, origincol);
1580 printw("CONGRATULATIONS!\n");
1581 printw("You won the game. That is a feat to be proud of.\n");
1582 row = originrow + 5;
1583 col = origincol;
1584 } else {
1585 move(msgrow, msgcol);
1586 printw("You got %d card", cardsoff);
1587 if (cardsoff > 1)
1588 printw("s");
1589 printw(" off ");
1590 move(msgrow, msgcol);
1591 row = moverow;
1592 col = movecol;
1593 }
1594 do {
1595 getcmd(row, col, "Play again (y or n)?");
1596 } while (srcpile != 'y' && srcpile != 'n');
1597 errmsg = TRUE;
1598 clearmsg();
1599 if (srcpile == 'y')
1600 return (FALSE);
1601 else
1602 return (TRUE);
1603 }
1604
1605 /*
1606 * procedure to clean up and exit
1607 */
1608 void
cleanup()1609 cleanup()
1610 {
1611
1612 total.thinktime += 1;
1613 status = NOBOX;
1614 updatebettinginfo();
1615 if (dbfd != -1) {
1616 lseek(dbfd, uid * sizeof(struct betinfo), 0);
1617 write(dbfd, (char *)&total, sizeof(total));
1618 close(dbfd);
1619 }
1620 clear();
1621 move(22,0);
1622 refresh();
1623 endwin();
1624 exit(0);
1625 /* NOTREACHED */
1626 }
1627
1628 /*
1629 * Field an interrupt.
1630 */
1631 void
askquit()1632 askquit()
1633 {
1634 move(msgrow, msgcol);
1635 printw("Really wish to quit? ");
1636 do {
1637 getcmd(moverow, movecol, "y or n?");
1638 } while (srcpile != 'y' && srcpile != 'n');
1639 clearmsg();
1640 if (srcpile == 'y')
1641 cleanup();
1642 signal(SIGINT, askquit);
1643 }
1644
1645 /*
1646 * Can you tell that this used to be a Pascal program?
1647 */
main(argc,argv)1648 main(argc, argv)
1649 int argc;
1650 char *argv[];
1651 {
1652 #ifdef MAXLOAD
1653 double vec[3];
1654
1655 loadav(vec);
1656 if (vec[2] >= MAXLOAD) {
1657 puts("The system load is too high. Try again later.");
1658 exit(0);
1659 }
1660 #endif
1661 signal(SIGINT, askquit);
1662 signal(SIGHUP, cleanup);
1663 signal(SIGTERM, cleanup);
1664 initscr();
1665 raw();
1666 noecho();
1667 initall();
1668 instruct();
1669 makeboard();
1670 for (;;) {
1671 startgame();
1672 movecard();
1673 if (finish())
1674 break;
1675 if (cardsoff == 52)
1676 makeboard();
1677 else
1678 cleanupboard();
1679 }
1680 cleanup();
1681 /* NOTREACHED */
1682 }
1683