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