1 /* Copyright (c) 1982 Regents of the University of California */
2 
3 static char sccsid[] = "@(#)canfield.c 4.5 05/10/83";
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 cleanupboard()
351 {
352 	int cnt, row, col;
353 	struct cardtype *ptr;
354 
355 	if (Cflag) {
356 		clearstat();
357 		for(ptr = stock, row = stockrow;
358 		    ptr != NIL;
359 		    ptr = ptr->next, row++) {
360 			move(row, sidecol);
361 			printw("     ");
362 		}
363 		move(row, sidecol);
364 		printw("     ");
365 		move(stockrow + 1, sidecol);
366 		printw("=---=");
367 		move(talonrow - 2, sidecol);
368 		printw("talon");
369 		move(talonrow - 1, sidecol);
370 		printw("=---=");
371 		move(talonrow + 1, sidecol);
372 		printw("=---=");
373 	}
374 	move(stockrow, sidecol);
375 	printw("|   |");
376 	move(talonrow, sidecol);
377 	printw("|   |");
378 	move(foundrow, fttlcol);
379 	printw("|   |  |   |  |   |  |   |");
380 	for (cnt = 0; cnt < 4; cnt++) {
381 		switch(cnt) {
382 		case 0:
383 			col = atabcol;
384 			break;
385 		case 1:
386 			col = btabcol;
387 			break;
388 		case 2:
389 			col = ctabcol;
390 			break;
391 		case 3:
392 			col = dtabcol;
393 			break;
394 		}
395 		for(ptr = tableau[cnt], row = tabrow;
396 		    ptr != NIL;
397 		    ptr = ptr->next, row++)
398 			removecard(col, row);
399 	}
400 }
401 
402 /* procedure to create a deck of cards */
403 initdeck(deck)
404 struct cardtype *deck[];
405 {
406 	int i;
407 	int scnt;
408 	char s;
409 	int r;
410 
411 	i = 0;
412 	for (scnt=0; scnt<4; scnt++) {
413 		s = suitmap[scnt];
414 		for (r=Ace; r<=King; r++) {
415 			deck[i] = &cards[i];
416 			cards[i].rank = r;
417 			cards[i].suit = s;
418 			cards[i].color = colormap[scnt];
419 			cards[i].next = NIL;
420 			i++;
421 		}
422 	}
423 }
424 
425 /* procedure to shuffle the deck */
426 shuffle(deck)
427 struct cardtype *deck[];
428 {
429 	int i,j;
430 	struct cardtype *temp;
431 
432 	for (i=0; i<decksize; i++) {
433 		deck[i]->visible = FALSE;
434 		deck[i]->paid = FALSE;
435 	}
436 	for (i = decksize-1; i>=0; i--) {
437 		j = random() % decksize;
438 		if (i != j) {
439 			temp = deck[i];
440 			deck[i] = deck[j];
441 			deck[j] = temp;
442 		}
443 	}
444 }
445 
446 /* procedure to remove the card from the board */
447 removecard(a, b)
448 {
449 	move(b, a);
450 	printw("   ");
451 }
452 
453 /* procedure to print the cards on the board */
454 printrank(a, b, cp, inverse)
455 struct cardtype *cp;
456 bool inverse;
457 {
458 	move(b, a);
459 	if (cp->rank != 10)
460 		addch(' ');
461 	if (inverse)
462 		standout();
463 	switch (cp->rank) {
464 		case 2: case 3: case 4: case 5: case 6: case 7:
465 		case 8: case 9: case 10:
466 			printw("%d", cp->rank);
467 			break;
468 		case Ace:
469 			addch('A');
470 			break;
471 		case Jack:
472 			addch('J');
473 			break;
474 		case Queen:
475 			addch('Q');
476 			break;
477 		case King:
478 			addch('K');
479 	}
480 	if (inverse)
481 		standend();
482 }
483 
484 printcard(a, b, cp)
485 int a,b;
486 struct cardtype *cp;
487 {
488 	if (cp == NIL)
489 		removecard(a, b);
490 	else if (cp->visible == FALSE) {
491 		move(b, a);
492 		printw(" ? ");
493 	} else {
494 		bool inverse = (cp->suit == 'd' || cp->suit == 'h');
495 
496 		printrank(a, b, cp, inverse);
497 		if (inverse)
498 			standout();
499 		addch(cp->suit);
500 		if (inverse)
501 			standend();
502 	}
503 }
504 
505 /*
506  * procedure to move the top card from one location to the top
507  * of another location. The pointers always point to the top
508  * of the piles.
509  */
510 transit(source, dest)
511 struct cardtype **source, **dest;
512 {
513 	struct cardtype *temp;
514 
515 	temp = *source;
516 	*source = (*source)->next;
517 	temp->next = *dest;
518 	*dest = temp;
519 }
520 
521 /*
522  * Procedure to set the cards on the foundation base when available.
523  * Note that it is only called on a foundation pile at the beginning of
524  * the game, so the pile will have exactly one card in it.
525  */
526 
527 fndbase(cp, column, row)
528 struct cardtype **cp;
529 {
530 	bool nomore;
531 
532 	if (*cp != NIL)
533 		do {
534 			if ((*cp)->rank == basecard->rank) {
535 				base++;
536 				printcard(pilemap[base], foundrow, *cp);
537 				if (*cp == tableau[0])
538 					length[0] = length[0] - 1;
539 				if (*cp == tableau[1])
540 					length[1] = length[1] - 1;
541 				if (*cp == tableau[2])
542 					length[2] = length[2] - 1;
543 				if (*cp == tableau[3])
544 					length[3] = length[3] - 1;
545 				transit(cp, &found[base]);
546 				if (cp == &talon)
547 					usedtalon();
548 				if (cp == &stock)
549 					usedstock();
550 				if (*cp != NIL) {
551 					printcard(column, row, *cp);
552 					nomore = FALSE;
553 				} else {
554 					removecard(column, row);
555 					nomore = TRUE;
556 				}
557 				cardsoff++;
558 				if (infullgame) {
559 					this.wins += valuepercardup;
560 					total.wins += valuepercardup;
561 				}
562 			} else
563 				nomore = TRUE;
564 	} while (nomore == FALSE);
565 }
566 
567 /*
568  * procedure to initialize the things necessary for the game
569  */
570 initgame()
571 {
572 	register i;
573 
574 	for (i=0; i<18; i++) {
575 		deck[i]->visible = TRUE;
576 		deck[i]->paid = TRUE;
577 	}
578 	stockcnt = 13;
579 	stock = deck[12];
580 	for (i=12; i>=1; i--)
581 		deck[i]->next = deck[i - 1];
582 	deck[0]->next = NIL;
583 	found[0] = deck[13];
584 	deck[13]->next = NIL;
585 	for (i=1; i<4; i++)
586 		found[i] = NIL;
587 	basecard = found[0];
588 	for (i=14; i<18; i++) {
589 		tableau[i - 14] = deck[i];
590 		deck[i]->next = NIL;
591 	}
592 	for (i=0; i<4; i++) {
593 		bottom[i] = tableau[i];
594 		length[i] = tabrow;
595 	}
596 	hand = deck[18];
597 	for (i=18; i<decksize-1; i++)
598 		deck[i]->next = deck[i + 1];
599 	deck[decksize-1]->next = NIL;
600 	talon = NIL;
601 	base = 0;
602 	cinhand = 34;
603 	taloncnt = 0;
604 	timesthru = 0;
605 	cardsoff = 1;
606 	coldrow = ctoprow;
607 	coldcol = cinitcol;
608 	cnewrow = ctoprow;
609 	cnewcol = cinitcol + cwidthcol;
610 }
611 
612 /* procedure to print the beginning cards and to start each game */
613 startgame()
614 {
615 	register int j;
616 
617 	shuffle(deck);
618 	initgame();
619 	this.hand = costofhand;
620 	total.hand += costofhand;
621 	this.inspection = 0;
622 	this.game = 0;
623 	this.runs = 0;
624 	this.information = 0;
625 	this.wins = 0;
626 	infullgame = FALSE;
627 	startedgame = FALSE;
628 	printcard(foundcol, foundrow, found[0]);
629 	printcard(stockcol, stockrow, stock);
630 	printcard(atabcol, tabrow, tableau[0]);
631 	printcard(btabcol, tabrow, tableau[1]);
632 	printcard(ctabcol, tabrow, tableau[2]);
633 	printcard(dtabcol, tabrow, tableau[3]);
634 	printcard(taloncol, talonrow, talon);
635 	move(foundrow - 2, basecol);
636 	printw("Base");
637 	move(foundrow - 1, basecol);
638 	printw("Rank");
639 	printrank(basecol, foundrow, found[0], 0);
640 	for (j=0; j<=3; j++)
641 		fndbase(&tableau[j], pilemap[j], tabrow);
642 	fndbase(&stock, stockcol, stockrow);
643 	showstat();	/* show card counting info to cheaters */
644 	movetotalon();
645 	updatebettinginfo();
646 }
647 
648 
649 /* procedure to clear the message printed from an error */
650 clearmsg()
651 {
652 	int i;
653 
654 	if (errmsg == TRUE) {
655 		errmsg = FALSE;
656 		move(msgrow, msgcol);
657 		for (i=0; i<25; i++)
658 			addch(' ');
659 		refresh();
660 	}
661 }
662 
663 /* procedure to print an error message if the move is not listed */
664 dumberror()
665 {
666 	errmsg = TRUE;
667 	move(msgrow, msgcol);
668 	printw("Not a proper move       ");
669 }
670 
671 /* procedure to print an error message if the move is not possible */
672 destinerror()
673 {
674 	errmsg = TRUE;
675 	move(msgrow, msgcol);
676 	printw("Error: Can't move there");
677 }
678 
679 /* function to see if the source has cards in it */
680 bool
681 notempty(cp)
682 struct cardtype *cp;
683 {
684 	if (cp == NIL) {
685 		errmsg = TRUE;
686 		move(msgrow, msgcol);
687 		printw("Error: no cards to move");
688 		return (FALSE);
689 	} else
690 		return (TRUE);
691 }
692 
693 
694 /* function to see if the rank of one card is less than another */
695 
696 bool
697 ranklower(cp1, cp2)
698 struct cardtype *cp1, *cp2;
699 {
700 	if (cp2->rank == Ace)
701 		if (cp1->rank == King)
702 			return (TRUE);
703 		else
704 			return (FALSE);
705 	else if (cp1->rank + 1 == cp2->rank)
706 		return (TRUE);
707 	else
708 		return (FALSE);
709 }
710 
711 /* function to check the cardcolor for moving to a tableau */
712 bool
713 diffcolor(cp1, cp2)
714 struct cardtype *cp1, *cp2;
715 {
716 	if (cp1->color == cp2->color)
717 		return (FALSE);
718 	else
719 		return (TRUE);
720 }
721 
722 /* function to see if the card can move to the tableau */
723 bool
724 tabok(cp, des)
725 struct cardtype *cp;
726 {
727 	if ((cp == stock) && (tableau[des] == NIL))
728 		return (TRUE);
729 	else if (tableau[des] == NIL)
730 		if (stock == NIL)
731 			return (TRUE);
732 		else
733 			return (FALSE);
734 	else if (ranklower(cp, tableau[des]) && diffcolor(cp, tableau[des]))
735 		return (TRUE);
736 	else
737 		return (FALSE);
738 }
739 
740 /*
741  * procedure to turn the cards onto the talon from the deck
742  */
743 movetotalon()
744 {
745 	int i, fin;
746 
747 	if (cinhand >= 3)
748 		fin = 3;
749 	else if (cinhand > 0)
750 		fin = cinhand;
751 	else if (talon != NIL) {
752 		timesthru++;
753 		errmsg = TRUE;
754 		move(msgrow, msgcol);
755 		if (timesthru != 4) {
756 			printw("Talon is now the new hand");
757 			this.runs += costofrunthroughhand;
758 			total.runs += costofrunthroughhand;
759 			while (talon != NIL) {
760 				transit(&talon, &hand);
761 				cinhand++;
762 			}
763 			if (cinhand >= 3)
764 				fin = 3;
765 			else
766 				fin = cinhand;
767 			taloncnt = 0;
768 			coldrow = ctoprow;
769 			coldcol = cinitcol;
770 			cnewrow = ctoprow;
771 			cnewcol = cinitcol + cwidthcol;
772 			clearstat();
773 			showstat();
774 		} else {
775 			fin = 0;
776 			done = TRUE;
777 			printw("I believe you have lost");
778 			refresh();
779 			sleep(5);
780 		}
781 	} else {
782 		errmsg = TRUE;
783 		move(msgrow, msgcol);
784 		printw("Talon and hand are empty");
785 		fin = 0;
786 	}
787 	for (i=0; i<fin; i++) {
788 		transit(&hand, &talon);
789 		INCRHAND(cnewrow, cnewcol);
790 		INCRHAND(coldrow, coldcol);
791 		removecard(cnewcol, cnewrow);
792 		if (i == fin - 1)
793 			talon->visible = TRUE;
794 		if (Cflag) {
795 			if (talon->paid == FALSE && talon->visible == TRUE) {
796 				this.information += costofinformation;
797 				total.information += costofinformation;
798 				talon->paid = TRUE;
799 			}
800 			printcard(coldcol, coldrow, talon);
801 		}
802 	}
803 	if (fin != 0) {
804 		printcard(taloncol, talonrow, talon);
805 		cinhand -= fin;
806 		taloncnt += fin;
807 		if (Cflag) {
808 			move(handstatrow, handstatcol);
809 			printw("%3d", cinhand);
810 			move(talonstatrow, talonstatcol);
811 			printw("%3d", taloncnt);
812 		}
813 		fndbase(&talon, taloncol, talonrow);
814 	}
815 }
816 
817 
818 /*
819  * procedure to print card counting info on screen
820  */
821 showstat()
822 {
823 	int row, col;
824 	register struct cardtype *ptr;
825 
826 	if (!Cflag)
827 		return;
828 	move(talonstatrow, talonstatcol - 7);
829 	printw("Talon: %3d", taloncnt);
830 	move(handstatrow, handstatcol - 7);
831 	printw("Hand:  %3d", cinhand);
832 	move(stockstatrow, stockstatcol - 7);
833 	printw("Stock: %3d", stockcnt);
834 	for ( row = coldrow, col = coldcol, ptr = talon;
835 	      ptr != NIL;
836 	      ptr = ptr->next ) {
837 		if (ptr->paid == FALSE && ptr->visible == TRUE) {
838 			ptr->paid = TRUE;
839 			this.information += costofinformation;
840 			total.information += costofinformation;
841 		}
842 		printcard(col, row, ptr);
843 		DECRHAND(row, col);
844 	}
845 	for ( row = cnewrow, col = cnewcol, ptr = hand;
846 	      ptr != NIL;
847 	      ptr = ptr->next ) {
848 		if (ptr->paid == FALSE && ptr->visible == TRUE) {
849 			ptr->paid = TRUE;
850 			this.information += costofinformation;
851 			total.information += costofinformation;
852 		}
853 		INCRHAND(row, col);
854 		printcard(col, row, ptr);
855 	}
856 }
857 
858 /*
859  * procedure to clear card counting info from screen
860  */
861 clearstat()
862 {
863 	int row;
864 
865 	move(talonstatrow, talonstatcol - 7);
866 	printw("          ");
867 	move(handstatrow, handstatcol - 7);
868 	printw("          ");
869 	move(stockstatrow, stockstatcol - 7);
870 	printw("          ");
871 	for ( row = ctoprow ; row <= cbotrow ; row++ ) {
872 		move(row, cinitcol);
873 		printw("%56s", " ");
874 	}
875 }
876 
877 
878 /*
879  * procedure to update card counting base
880  */
881 usedtalon()
882 {
883 	removecard(coldcol, coldrow);
884 	DECRHAND(coldrow, coldcol);
885 	if (talon != NIL && (talon->visible == FALSE)) {
886 		talon->visible = TRUE;
887 		if (Cflag) {
888 			this.information += costofinformation;
889 			total.information += costofinformation;
890 			talon->paid = TRUE;
891 			printcard(coldcol, coldrow, talon);
892 		}
893 	}
894 	taloncnt--;
895 	if (Cflag) {
896 		move(talonstatrow, talonstatcol);
897 		printw("%3d", taloncnt);
898 	}
899 }
900 
901 
902 /*
903  * procedure to update stock card counting base
904  */
905 usedstock()
906 {
907 	stockcnt--;
908 	if (Cflag) {
909 		move(stockstatrow, stockstatcol);
910 		printw("%3d", stockcnt);
911 	}
912 }
913 
914 /*
915  * let 'em know how they lost!
916  */
917 showcards()
918 {
919 	register struct cardtype *ptr;
920 	int row;
921 
922 	if (!Cflag)
923 		return;
924 	for (ptr = talon; ptr != NIL; ptr = ptr->next) {
925 		ptr->visible = TRUE;
926 		ptr->paid = TRUE;
927 	}
928 	for (ptr = hand; ptr != NIL; ptr = ptr->next) {
929 		ptr->visible = TRUE;
930 		ptr->paid = TRUE;
931 	}
932 	showstat();
933 	move(stockrow + 1, sidecol);
934 	printw("     ");
935 	move(talonrow - 2, sidecol);
936 	printw("     ");
937 	move(talonrow - 1, sidecol);
938 	printw("     ");
939 	move(talonrow, sidecol);
940 	printw("     ");
941 	move(talonrow + 1, sidecol);
942 	printw("     ");
943 	for (ptr = stock, row = stockrow; ptr != NIL; ptr = ptr->next, row++) {
944 		move(row, stockcol - 1);
945 		printw("|   |");
946 		printcard(stockcol, row, ptr);
947 	}
948 	if (stock == NIL) {
949 		move(row, stockcol - 1);
950 		printw("|   |");
951 		row++;
952 	}
953 	move(handstatrow, handstatcol - 7);
954 	printw("          ");
955 	move(row, stockcol - 1);
956 	printw("=---=");
957 	getcmd(moverow, movecol, "Hit return to exit");
958 }
959 
960 /*
961  * procedure to update the betting values
962  */
963 updatebettinginfo()
964 {
965 	long thiscosts, totalcosts;
966 	time_t now;
967 	register long dollars;
968 
969 	thiscosts = this.hand + this.inspection + this.game +
970 		this.runs + this.information + this.thinktime;
971 	totalcosts = total.hand + total.inspection + total.game +
972 		total.runs + total.information + total.thinktime;
973 	this.worth = this.wins - thiscosts;
974 	total.worth = total.wins - totalcosts;
975 	time(&now);
976 	dollars = (now - acctstart) / secondsperdollar;
977 	if (dollars > 0) {
978 		this.thinktime += dollars;
979 		total.thinktime += dollars;
980 		acctstart += dollars * secondsperdollar;
981 	}
982 	if (status != BETTINGBOX)
983 		return;
984 	move(tboxrow + 3, boxcol + 13);
985 	printw("%4d%9d", this.hand, total.hand);
986 	move(tboxrow + 4, boxcol + 13);
987 	printw("%4d%9d", this.inspection, total.inspection);
988 	move(tboxrow + 5, boxcol + 13);
989 	printw("%4d%9d", this.game, total.game);
990 	move(tboxrow + 6, boxcol + 13);
991 	printw("%4d%9d", this.runs, total.runs);
992 	move(tboxrow + 7, boxcol + 13);
993 	printw("%4d%9d", this.information, total.information);
994 	move(tboxrow + 8, boxcol + 13);
995 	printw("%4d%9d", this.thinktime, total.thinktime);
996 	move(tboxrow + 9, boxcol + 13);
997 	printw("%4d%9d", thiscosts, totalcosts);
998 	move(tboxrow + 10, boxcol + 13);
999 	printw("%4d%9d", this.wins, total.wins);
1000 	move(tboxrow + 11, boxcol + 13);
1001 	printw("%4d%9d", this.worth, total.worth);
1002 }
1003 
1004 /*
1005  * procedure to move a card from the stock or talon to the tableau
1006  */
1007 simpletableau(cp, des)
1008 struct cardtype **cp;
1009 {
1010 	int origin;
1011 
1012 	if (notempty(*cp)) {
1013 		if (tabok(*cp, des)) {
1014 			if (*cp == stock)
1015 				origin = stk;
1016 			else
1017 				origin = tal;
1018 			if (tableau[des] == NIL)
1019 				bottom[des] = *cp;
1020 			transit(cp, &tableau[des]);
1021 			length[des]++;
1022 			printcard(pilemap[des], length[des], tableau[des]);
1023 			timesthru = 0;
1024 			if (origin == stk) {
1025 				usedstock();
1026 				printcard(stockcol, stockrow, stock);
1027 			} else {
1028 				usedtalon();
1029 				printcard(taloncol, talonrow, talon);
1030 			}
1031 		} else
1032 			destinerror();
1033 	}
1034 }
1035 
1036 
1037 tabprint(sour, des)
1038 {
1039 	int dlength, slength, i;
1040 	struct cardtype *tempcard;
1041 
1042 	for (i=tabrow; i<=length[sour]; i++)
1043 		removecard(pilemap[sour], i);
1044 	dlength = length[des] + 1;
1045 	slength = length[sour];
1046 	if (slength == tabrow)
1047 		printcard(pilemap[des], dlength, tableau[sour]);
1048 	else
1049 		while (slength != tabrow - 1) {
1050 			tempcard = tableau[sour];
1051 			for (i=1; i<=slength-tabrow; i++)
1052 			    tempcard = tempcard->next;
1053 			printcard(pilemap[des], dlength, tempcard);
1054 			slength--;
1055 			dlength++;
1056 		}
1057 }
1058 
1059 /* procedure to move from the tableau to the tableau */
1060 tabtotab(sour, des)
1061 {
1062 	struct cardtype *temp;
1063 
1064 	if (notempty(tableau[sour])) {
1065 		if (tabok(bottom[sour], des)) {
1066 			tabprint(sour, des);
1067 			temp = bottom[sour];
1068 			bottom[sour] = NIL;
1069 			temp->next = tableau[des];
1070 			tableau[des] = tableau[sour];
1071 			tableau[sour] = NIL;
1072 			length[des] = length[des] + (length[sour] - (tabrow - 1));
1073 			length[sour] = tabrow - 1;
1074 			timesthru = 0;
1075 		} else
1076 			destinerror();
1077 	}
1078 }
1079 
1080 
1081 /* functions to see if the card can go onto the foundation */
1082 bool
1083 rankhigher(cp, let)
1084 struct cardtype *cp;
1085 {
1086 	if (found[let]->rank == King)
1087 		if (cp->rank == Ace)
1088 			return(TRUE);
1089 		else
1090 			return(FALSE);
1091 	else if (cp->rank - 1 == found[let]->rank)
1092 		return(TRUE);
1093 	else
1094 		return(FALSE);
1095 }
1096 
1097 samesuit(cp, let)
1098 struct cardtype *cp;
1099 {
1100 	if (cp->suit == found[let]->suit)
1101 		return (TRUE);
1102 	else
1103 		return (FALSE);
1104 }
1105 
1106 /* procedure to move a card to the correct foundation pile */
1107 
1108 movetofound(cp, source)
1109 struct cardtype **cp;
1110 {
1111 	tempbase = 0;
1112 	mtfdone = FALSE;
1113 	if (notempty(*cp)) {
1114 		do {
1115 			if (found[tempbase] != NIL)
1116 				if (rankhigher(*cp, tempbase)
1117 				    && samesuit(*cp, tempbase)) {
1118 					if (*cp == stock)
1119 						mtforigin = stk;
1120 					else if (*cp == talon)
1121 						mtforigin = tal;
1122 					else
1123 						mtforigin = tab;
1124 					transit(cp, &found[tempbase]);
1125 					printcard(pilemap[tempbase],
1126 						foundrow, found[tempbase]);
1127 					timesthru = 0;
1128 					if (mtforigin == stk) {
1129 						usedstock();
1130 						printcard(stockcol, stockrow, stock);
1131 					} else if (mtforigin == tal) {
1132 						usedtalon();
1133 						printcard(taloncol, talonrow, talon);
1134 					} else {
1135 						removecard(pilemap[source], length[source]);
1136 						length[source]--;
1137 					}
1138 					cardsoff++;
1139 					if (infullgame) {
1140 						this.wins += valuepercardup;
1141 						total.wins += valuepercardup;
1142 					}
1143 					mtfdone = TRUE;
1144 				} else
1145 					tempbase++;
1146 			else
1147 				tempbase++;
1148 		} while ((tempbase != 4) && !mtfdone);
1149 		if (!mtfdone)
1150 			destinerror();
1151 	}
1152 }
1153 
1154 
1155 /* procedure to get a command */
1156 
1157 getcmd(row, col, cp)
1158 	int row, col;
1159 	char *cp;
1160 {
1161 	char cmd[2], ch;
1162 	int i;
1163 
1164 	i = 0;
1165 	move(row, col);
1166 	printw("%-24s", cp);
1167 	col += 1 + strlen(cp);
1168 	move(row, col);
1169 	refresh();
1170 	do {
1171 		ch = getch() & 0177;
1172 		if (ch >= 'A' && ch <= 'Z')
1173 			ch += ('a' - 'A');
1174 		if (ch == '\f') {
1175 			wrefresh(curscr);
1176 			refresh();
1177 		} else if (i >= 2 && ch != _tty.sg_erase && ch != _tty.sg_kill) {
1178 			if (ch != '\n' && ch != '\r' && ch != ' ')
1179 				write(1, "\007", 1);
1180 		} else if (ch == _tty.sg_erase && i > 0) {
1181 			printw("\b \b");
1182 			refresh();
1183 			i--;
1184 		} else if (ch == _tty.sg_kill && i > 0) {
1185 			while (i > 0) {
1186 				printw("\b \b");
1187 				i--;
1188 			}
1189 			refresh();
1190 		} else if (ch == '\032') {	/* Control-Z */
1191 			suspend();
1192 			move(row, col + i);
1193 			refresh();
1194 		} else if (isprint(ch)) {
1195 			cmd[i++] = ch;
1196 			addch(ch);
1197 			refresh();
1198 		}
1199 	} while (ch != '\n' && ch != '\r' && ch != ' ');
1200 	srcpile = cmd[0];
1201 	destpile = cmd[1];
1202 }
1203 
1204 /* Suspend the game (shell escape if no process control on system) */
1205 
1206 suspend()
1207 {
1208 #ifndef SIGTSTP
1209 	char *sh;
1210 #endif
1211 
1212 	move(21, 0);
1213 	refresh();
1214 	endwin();
1215 	fflush(stdout);
1216 #ifdef SIGTSTP
1217 	kill(getpid(), SIGTSTP);
1218 #else
1219 	sh = getenv("SHELL");
1220 	if (sh == NULL)
1221 		sh = "/bin/sh";
1222 	system(sh);
1223 #endif
1224 	raw();
1225 	noecho();
1226 }
1227 
1228 /* procedure to evaluate and make the specific moves */
1229 
1230 movecard()
1231 {
1232 	int source, dest;
1233 	char osrcpile, odestpile;
1234 
1235 	done = FALSE;
1236 	errmsg = FALSE;
1237 	do {
1238 		if (talon == NIL && hand != NIL)
1239 			movetotalon();
1240 		if (cardsoff == 52) {
1241 			refresh();
1242 			srcpile = 'q';
1243 		} else
1244 			getcmd(moverow, movecol, "Move:");
1245 		clearmsg();
1246 		if (srcpile >= '1' && srcpile <= '4')
1247 			source = (int) (srcpile - '1');
1248 		if (destpile >= '1' && destpile <= '4')
1249 			dest = (int) (destpile - '1');
1250 		if (!startedgame &&
1251 		    (srcpile == 't' || srcpile == 's' || srcpile == 'h' ||
1252 		     srcpile == '1' || srcpile == '2' || srcpile == '3' ||
1253 		     srcpile == '4')) {
1254 			startedgame = TRUE;
1255 			osrcpile = srcpile;
1256 			odestpile = destpile;
1257 			if (status != BETTINGBOX)
1258 				srcpile = 'y';
1259 			else do {
1260 				getcmd(moverow, movecol, "Inspect game?");
1261 			} while (srcpile != 'y' && srcpile != 'n');
1262 			if (srcpile == 'n') {
1263 				srcpile = 'q';
1264 			} else {
1265 				this.inspection += costofinspection;
1266 				total.inspection += costofinspection;
1267 				srcpile = osrcpile;
1268 				destpile = odestpile;
1269 			}
1270 		}
1271 		switch (srcpile) {
1272 			case 't':
1273 				if (destpile == 'f' || destpile == 'F')
1274 					movetofound(&talon, source);
1275 				else if (destpile >= '1' && destpile <= '4')
1276 					simpletableau(&talon, dest);
1277 				else
1278 					dumberror();
1279 				break;
1280 			case 's':
1281 				if (destpile == 'f' || destpile == 'F')
1282 					movetofound(&stock, source);
1283 				else if (destpile >= '1' && destpile <= '4')
1284 					simpletableau(&stock, dest);
1285 				else dumberror();
1286 				break;
1287 			case 'h':
1288 				if (destpile != 't' && destpile != 'T') {
1289 					dumberror();
1290 					break;
1291 				}
1292 				if (infullgame) {
1293 					movetotalon();
1294 					break;
1295 				}
1296 				if (status == BETTINGBOX) {
1297 					do {
1298 						getcmd(moverow, movecol,
1299 							"Buy game?");
1300 					} while (srcpile != 'y' &&
1301 						 srcpile != 'n');
1302 					if (srcpile == 'n') {
1303 						showcards();
1304 						done = TRUE;
1305 						break;
1306 					}
1307 				}
1308 				infullgame = TRUE;
1309 				this.wins += valuepercardup * cardsoff;
1310 				total.wins += valuepercardup * cardsoff;
1311 				this.game += costofgame;
1312 				total.game += costofgame;
1313 				movetotalon();
1314 				break;
1315 			case 'q':
1316 				showcards();
1317 				done = TRUE;
1318 				break;
1319 			case 'b':
1320 				printtopbettingbox();
1321 				printbottombettingbox();
1322 				status = BETTINGBOX;
1323 				break;
1324 			case 'x':
1325 				clearabovemovebox();
1326 				clearbelowmovebox();
1327 				status = NOBOX;
1328 				break;
1329 			case 'i':
1330 				printtopinstructions();
1331 				printbottominstructions();
1332 				status = INSTRUCTIONBOX;
1333 				break;
1334 			case 'c':
1335 				Cflag = !Cflag;
1336 				if (Cflag)
1337 					showstat();
1338 				else
1339 					clearstat();
1340 				break;
1341 			case '1': case '2': case '3': case '4':
1342 				if (destpile == 'f' || destpile == 'F')
1343 					movetofound(&tableau[source], source);
1344 				else if (destpile >= '1' && destpile <= '4')
1345 					tabtotab(source, dest);
1346 				else dumberror();
1347 				break;
1348 			default:
1349 				dumberror();
1350 		}
1351 		fndbase(&stock, stockcol, stockrow);
1352 		fndbase(&talon, taloncol, talonrow);
1353 		updatebettinginfo();
1354 	} while (!done);
1355 }
1356 
1357 char *basicinstructions[] = {
1358 	"Here are brief instuctions to the game of Canfield:\n\n",
1359 	"     If you have never played solitaire before, it is recom-\n",
1360 	"mended  that  you  consult  a solitaire instruction book. In\n",
1361 	"Canfield, tableau cards may be built on each other  downward\n",
1362 	"in  alternate colors. An entire pile must be moved as a unit\n",
1363 	"in building. Top cards of the piles are available to be able\n",
1364 	"to be played on foundations, but never into empty spaces.\n\n",
1365 	"     Spaces must be filled from the stock. The top  card  of\n",
1366 	"the  stock  also is available to be played on foundations or\n",
1367 	"built on tableau piles. After the stock  is  exhausted,  ta-\n",
1368 	"bleau spaces may be filled from the talon and the player may\n",
1369 	"keep them open until he wishes to use them.\n\n",
1370 	"     Cards are dealt from the hand to the  talon  by  threes\n",
1371 	"and  this  repeats until there are no more cards in the hand\n",
1372 	"or the player quits. To have cards dealt onto the talon  the\n",
1373 	"player  types  'ht'  for his move. Foundation base cards are\n",
1374 	"also automatically moved to the foundation when they  become\n",
1375 	"available.\n\n",
1376 	"push any key when you are finished: ",
1377 	0 };
1378 
1379 char *bettinginstructions[] = {
1380 	"     The rules for betting are  somewhat  less  strict  than\n",
1381 	"those  used in the official version of the game. The initial\n",
1382 	"deal costs $13. You may quit at this point  or  inspect  the\n",
1383 	"game.  Inspection  costs  $13 and allows you to make as many\n",
1384 	"moves as is possible without moving any cards from your hand\n",
1385 	"to  the  talon.  (the initial deal places three cards on the\n",
1386 	"talon; if all these cards are  used,  three  more  are  made\n",
1387 	"available)  Finally, if the game seems interesting, you must\n",
1388 	"pay the final installment of $26.  At  this  point  you  are\n",
1389 	"credited  at the rate of $5 for each card on the foundation;\n",
1390 	"as the game progresses you are credited  with  $5  for  each\n",
1391 	"card  that is moved to the foundation.  Each run through the\n",
1392 	"hand after the first costs $5.  The  card  counting  feature\n",
1393 	"costs  $1  for  each unknown card that is identified. If the\n",
1394 	"information is toggled on, you are only  charged  for  cards\n",
1395 	"that  became  visible  since it was last turned on. Thus the\n",
1396 	"maximum cost of information is $34.  Playing time is charged\n",
1397 	"at a rate of $1 per minute.\n\n",
1398 	"push any key when you are finished: ",
1399 	0 };
1400 
1401 /*
1402  * procedure to printout instructions
1403  */
1404 
1405 instruct()
1406 {
1407 	register char **cp;
1408 
1409 	move(originrow, origincol);
1410 	printw("This is the game of solitaire called Canfield.  Do\n");
1411 	printw("you want instructions for the game?");
1412 	do {
1413 		getcmd(originrow + 3, origincol, "y or n?");
1414 	} while (srcpile != 'y' && srcpile != 'n');
1415 	if (srcpile == 'n')
1416 		return;
1417 	clear();
1418 	for (cp = basicinstructions; *cp != 0; cp++)
1419 		printw(*cp);
1420 	refresh();
1421 	getch();
1422 	clear();
1423 	move(originrow, origincol);
1424 	printw("Do you want instructions for betting?");
1425 	do {
1426 		getcmd(originrow + 2, origincol, "y or n?");
1427 	} while (srcpile != 'y' && srcpile != 'n');
1428 	if (srcpile == 'n')
1429 		return;
1430 	clear();
1431 	for (cp = bettinginstructions; *cp != 0; cp++)
1432 		printw(*cp);
1433 	refresh();
1434 	getch();
1435 }
1436 
1437 /* procedure to initialize the game */
1438 initall()
1439 {
1440 	int uid, i;
1441 
1442 	srandom(getpid());
1443 	time(&acctstart);
1444 	initdeck(deck);
1445 	uid = getuid();
1446 	if (uid < 0)
1447 		return;
1448 	dbfd = open("/usr/games/lib/cfscores", 2);
1449 	if (dbfd < 0)
1450 		return;
1451 	i = lseek(dbfd, uid * sizeof(struct betinfo), 0);
1452 	if (i < 0) {
1453 		close(dbfd);
1454 		dbfd = -1;
1455 		return;
1456 	}
1457 	i = read(dbfd, (char *)&total, sizeof(total));
1458 	if (i < 0) {
1459 		close(dbfd);
1460 		dbfd = -1;
1461 		return;
1462 	}
1463 	lseek(dbfd, uid * sizeof(struct betinfo), 0);
1464 }
1465 
1466 /*
1467  * procedure to end the game
1468  */
1469 bool
1470 finish()
1471 {
1472 	int row, col;
1473 
1474 	if (cardsoff == 52) {
1475 		clear();
1476 		refresh();
1477 		move(originrow, origincol);
1478 		printw("CONGRATULATIONS!\n");
1479 		printw("You won the game. That is a feat to be proud of.\n");
1480 		move(originrow + 4, origincol);
1481 		printw("Wish to play again?     ");
1482 		row = originrow + 5;
1483 		col = origincol;
1484 	} else {
1485 		move(msgrow, msgcol);
1486 		printw("You got %d card", cardsoff);
1487 		if (cardsoff > 1)
1488 			printw("s");
1489 		printw(" off    ");
1490 		getcmd(moverow, movecol, "Hit return to continue");
1491 		move(msgrow, msgcol);
1492 		printw("Wish to play again?     ");
1493 		row = moverow;
1494 		col = movecol;
1495 	}
1496 	do {
1497 		getcmd(row, col, "y or n?");
1498 	} while (srcpile != 'y' && srcpile != 'n');
1499 	errmsg = TRUE;
1500 	clearmsg();
1501 	if (srcpile == 'y')
1502 		return (FALSE);
1503 	else
1504 		return (TRUE);
1505 }
1506 
1507 /*
1508  * Field an interrupt.
1509  */
1510 askquit()
1511 {
1512 	move(msgrow, msgcol);
1513 	printw("Really wish to quit?    ");
1514 	do {
1515 		getcmd(moverow, movecol, "y or n?");
1516 	} while (srcpile != 'y' && srcpile != 'n');
1517 	clearmsg();
1518 	if (srcpile == 'y')
1519 		cleanup();
1520 	signal(SIGINT, askquit);
1521 }
1522 
1523 /*
1524  * procedure to clean up and exit
1525  */
1526 cleanup()
1527 {
1528 
1529 	total.thinktime += 1;
1530 	if (dbfd != -1) {
1531 		write(dbfd, (char *)&total, sizeof(total));
1532 		close(dbfd);
1533 	}
1534 	clear();
1535 	move(22,0);
1536 	refresh();
1537 	endwin();
1538 	exit(0);
1539 	/* NOTREACHED */
1540 }
1541 
1542 main(argc, argv)
1543 	int argc;
1544 	char *argv[];
1545 {
1546 #ifdef MAXLOAD
1547 	double vec[3];
1548 
1549 	loadav(vec);
1550 	if (vec[2] >= MAXLOAD) {
1551 		puts("The system load is too high.  Try again later.");
1552 		exit(0);
1553 	}
1554 #endif
1555 	signal(SIGINT, askquit);
1556 	signal(SIGHUP, cleanup);
1557 	signal(SIGTERM, cleanup);
1558 	initscr();
1559 	raw();
1560 	noecho();
1561 	initall();
1562 	instruct();
1563 	makeboard();
1564 	for (;;) {
1565 		startgame();
1566 		movecard();
1567 		if (finish())
1568 			break;
1569 		if (cardsoff == 52)
1570 			makeboard();
1571 		else
1572 			cleanupboard();
1573 	}
1574 	cleanup();
1575 	/* NOTREACHED */
1576 }
1577