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