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