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