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