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