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