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