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