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