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