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