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