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