xref: /csrg-svn/games/cribbage/crib.c (revision 7937)
1 # include	<curses.h>
2 # include	<signal.h>
3 # include	"deck.h"
4 # include	"cribbage.h"
5 # include	"cribcur.h"
6 
7 
8 # define	LOGFILE		"/usr/games/lib/criblog"
9 # define	INSTRCMD	"ul /usr/games/lib/crib.instr | more -f"
10 
11 
12 main(argc, argv)
13 int	argc;
14 char	*argv[];
15 {
16 	register  char		*p;
17 	BOOLEAN			playing;
18 	char			*s;		/* for reading arguments */
19 	char			bust;		/* flag for arg reader */
20 	FILE			*f;
21 	FILE			*fopen();
22 	char			*getline();
23 	int			bye();
24 
25 	while (--argc > 0) {
26 	    if ((*++argv)[0] != '-') {
27 		fprintf(stderr, "\n\ncribbage: usage is 'cribbage [-eqr]'\n");
28 		exit(1);
29 	    }
30 	    bust = FALSE;
31 	    for (s = argv[0] + 1; *s != NULL; s++) {
32 		switch (*s) {
33 		    case 'e':
34 			explain = TRUE;
35 			break;
36 		    case 'q':
37 			quiet = TRUE;
38 			break;
39 		    case 'r':
40 			rflag = TRUE;
41 			break;
42 		    default:
43 			fprintf(stderr, "\n\ncribbage: usage is 'cribbage [-eqr]'\n");
44 			exit(2);
45 			break;
46 		}
47 		if (bust)
48 		    break;
49 	    }
50 	}
51 
52 	initscr();
53 	signal(SIGINT, bye);
54 	crmode();
55 	noecho();
56 	Playwin = subwin(stdscr, PLAY_Y, PLAY_X, 0, 0);
57 	Tablewin = subwin(stdscr, TABLE_Y, TABLE_X, 0, PLAY_X);
58 	Compwin = subwin(stdscr, COMP_Y, COMP_X, 0, TABLE_X + PLAY_X);
59 	leaveok(Playwin, TRUE);
60 	leaveok(Tablewin, TRUE);
61 	leaveok(Compwin, TRUE);
62 
63 	if (!quiet) {
64 	    msg("Do you need instructions for cribbage? ");
65 	    if (getuchar() == 'Y') {
66 		system(INSTRCMD);
67 		msg("For the rules of this program, do \"man cribbage\"");
68 	    }
69 	}
70 	playing = TRUE;
71 	do {
72 	    makeboard();
73 	    msg(quiet ? "L or S? " : "Long (to 121) or Short (to 61)? ");
74 	    glimit = (getuchar() == 'S' ? SGAME : LGAME);
75 	    game();
76 	    msg("Another game? ");
77 	    playing = (getuchar() == 'Y');
78 	} while (playing);
79 
80 	if ((f = fopen(LOGFILE, "a")) != NULL) {
81 	    fprintf(f, "Won %5.5d, Lost %5.5d\n",  cgames, pgames);
82 	    fclose(f);
83 	}
84 
85 	bye();
86 }
87 
88 /*
89  * bye:
90  *	Leave the program, cleaning things up as we go.
91  */
92 bye()
93 {
94 	signal(SIGINT, SIG_IGN);
95 	mvcur(0, COLS - 1, LINES - 1, 0);
96 	fflush(stdout);
97 	endwin();
98 	putchar('\n');
99 	exit(1);
100 }
101 
102 /*
103  * makeboard:
104  *	Print out the initial board on the screen
105  */
106 makeboard()
107 {
108     extern int	Lastscore[];
109 
110     mvaddstr(SCORE_Y + 0, SCORE_X, "+---------------------------------------+");
111     mvaddstr(SCORE_Y + 1, SCORE_X, "|                                       |");
112     mvaddstr(SCORE_Y + 2, SCORE_X, "| *.....:.....:.....:.....:.....:.....  |");
113     mvaddstr(SCORE_Y + 3, SCORE_X, "| *.....:.....:.....:.....:.....:.....  |");
114     mvaddstr(SCORE_Y + 4, SCORE_X, "|                                       |");
115     mvaddstr(SCORE_Y + 5, SCORE_X, "| *.....:.....:.....:.....:.....:.....  |");
116     mvaddstr(SCORE_Y + 6, SCORE_X, "| *.....:.....:.....:.....:.....:.....  |");
117     mvaddstr(SCORE_Y + 7, SCORE_X, "|                                       |");
118     mvaddstr(SCORE_Y + 8, SCORE_X, "+---------------------------------------+");
119     Lastscore[0] = -1;
120     Lastscore[1] = -1;
121 }
122 
123 /*
124  * game:
125  *	Play one game up to glimit points.  Actually, we only ASK the
126  *	player what card to turn.  We do a random one, anyway.
127  */
128 game()
129 {
130 	register int		i, j;
131 	BOOLEAN			flag;
132 	BOOLEAN			compcrib;
133 
134 	makedeck(deck);
135 	shuffle(deck);
136 	if (gamecount == 0) {
137 	    flag = TRUE;
138 	    do {
139 		if (!rflag) {				/* player cuts deck */
140 		    msg(quiet ? "Cut for crib? " :
141 			"Cut to see whose crib it is -- low card wins? ");
142 		    getline();
143 		}
144 		i = (rand() >> 4) % CARDS;		/* random cut */
145 		do {					/* comp cuts deck */
146 		    j = (rand() >> 4) % CARDS;
147 		} while (j == i);
148 		addmsg(quiet ? "You cut " : "You cut the ");
149 		msgcard(deck[i], FALSE);
150 		endmsg();
151 		addmsg(quiet ? "I cut " : "I cut the ");
152 		msgcard(deck[j], FALSE);
153 		endmsg();
154 		flag = (deck[i].rank == deck[j].rank);
155 		if (flag) {
156 		    msg(quiet ? "We tied..." :
157 			"We tied and have to try again...");
158 		    shuffle(deck);
159 		    continue;
160 		}
161 		else
162 		    compcrib = (deck[i].rank > deck[j].rank);
163 	    } while (flag);
164 	}
165 	else {
166 	    msg("Loser (%s) gets first crib.",  (iwon ? "you" : "me"));
167 	    compcrib = !iwon;
168 	}
169 
170 	pscore = cscore = 0;
171 	flag = TRUE;
172 	do {
173 	    shuffle(deck);
174 	    flag = !playhand(compcrib);
175 	    compcrib = !compcrib;
176 	    msg("You have %d points, I have %d.", pscore, cscore);
177 	} while (flag);
178 	++gamecount;
179 	if (cscore < pscore) {
180 	    if (glimit - cscore > 60) {
181 		msg("YOU DOUBLE SKUNKED ME!");
182 		pgames += 4;
183 	    }
184 	    else if (glimit - cscore > 30) {
185 		msg("YOU SKUNKED ME!");
186 		pgames += 2;
187 	    }
188 	    else {
189 		msg("YOU WON!");
190 		++pgames;
191 	    }
192 	    iwon = FALSE;
193 	}
194 	else {
195 	    if (glimit - pscore > 60) {
196 		msg("I DOUBLE SKUNKED YOU!");
197 		cgames += 4;
198 	    }
199 	    else if (glimit - pscore > 30) {
200 		msg("I SKUNKED YOU!");
201 		cgames += 2;
202 	    }
203 	    else {
204 		msg("I WON!");
205 		++cgames;
206 	    }
207 	    iwon = TRUE;
208 	}
209 	msg("I have won %d games, you have won %d", cgames, pgames);
210 }
211 
212 /*
213  * playhand:
214  *	Do up one hand of the game
215  */
216 playhand(mycrib)
217 BOOLEAN		mycrib;
218 {
219 	register int		deckpos;
220 	extern char		Msgbuf[];
221 
222 	werase(Compwin);
223 	wrefresh(Compwin);
224 	move(CRIB_Y, 0);
225 	clrtobot();
226 	mvaddstr(LINES - 1, 0, Msgbuf);
227 
228 	knownum = 0;
229 	deckpos = deal(mycrib);
230 	sorthand(chand, FULLHAND);
231 	sorthand(phand, FULLHAND);
232 	makeknown(chand, FULLHAND);
233 	prhand(phand, FULLHAND, Playwin);
234 	discard(mycrib);
235 	if (cut(mycrib, deckpos))
236 	    return TRUE;
237 	if (peg(mycrib))
238 	    return TRUE;
239 	werase(Tablewin);
240 	wrefresh(Tablewin);
241 	if (score(mycrib))
242 	    return TRUE;
243 	return FALSE;
244 }
245 
246 
247 
248 /*
249  * deal cards to both players from deck
250  */
251 
252 deal( mycrib )
253 {
254 	register  int		i, j;
255 
256 	j = 0;
257 	for( i = 0; i < FULLHAND; i++ )  {
258 	    if( mycrib )  {
259 		phand[i] = deck[j++];
260 		chand[i] = deck[j++];
261 	    }
262 	    else  {
263 		chand[i] = deck[j++];
264 		phand[i] = deck[j++];
265 	    }
266 	}
267 	return( j );
268 }
269 
270 /*
271  * discard:
272  *	Handle players discarding into the crib...
273  * Note: we call cdiscard() after prining first message so player doesn't wait
274  */
275 discard(mycrib)
276 BOOLEAN		mycrib;
277 {
278 	register char	*prompt;
279 	CARD		crd;
280 
281 	msg("It's %s crib...", (mycrib ? "my" : "your"));
282 	prompt = (quiet ? "Discard --> " : "Discard a card --> ");
283 	msg(prompt);
284 	cdiscard(mycrib);			/* puts best discard at end */
285 	crd = phand[infrom(phand, FULLHAND, prompt)];
286 	remove(crd, phand, FULLHAND);
287 	prhand(phand, FULLHAND, Playwin);
288 	crib[0] = crd;
289 /* next four lines same as last four except for cdiscard() */
290 	msg(prompt);
291 	crd = phand[infrom(phand, FULLHAND - 1, prompt)];
292 	remove(crd, phand, FULLHAND - 1);
293 	prhand(phand, FULLHAND, Playwin);
294 	crib[1] = crd;
295 	crib[2] = chand[4];
296 	crib[3] = chand[5];
297 	chand[4].rank = chand[4].suit = chand[5].rank = chand[5].suit = EMPTY;
298 }
299 
300 /*
301  * cut:
302  *	Cut the deck and set turnover.  Actually, we only ASK the
303  *	player what card to turn.  We do a random one, anyway.
304  */
305 cut(mycrib, pos)
306 BOOLEAN		mycrib;
307 int		pos;
308 {
309 	register int		i, cardx;
310 	BOOLEAN			win = FALSE;
311 
312 	if (mycrib) {
313 	    if (!rflag) {			/* random cut */
314 		msg(quiet ? "Cut the deck? " :
315 			"How many cards down do you wish to cut the deck? ");
316 		getline();
317 	    }
318 	    i = (rand() >> 4) % (CARDS - pos);
319 	    turnover = deck[i + pos];
320 	    addmsg(quiet ? "You cut " : "You cut the ");
321 	    msgcard(turnover, FALSE);
322 	    endmsg();
323 	    if (turnover.rank == JACK) {
324 		msg("I get two for his heels.");
325 		win = chkscr(&cscore,2 );
326 	    }
327 	    cardx = CRIB_X;
328 	}
329 	else {
330 	    i = (rand() >> 4) % (CARDS - pos) + pos;
331 	    turnover = deck[i];
332 	    addmsg(quiet ? "I cut " : "I cut the ");
333 	    msgcard(turnover, FALSE);
334 	    endmsg();
335 	    if (turnover.rank == JACK) {
336 		msg("You get two for his heels.");
337 		win = chkscr(&pscore, 2);
338 	    }
339 	    cardx = 0;
340 	}
341 	makeknown(&turnover, 1);
342 	mvaddstr(CRIB_Y, cardx + 1, "CRIB");
343 	prcard(stdscr, CRIB_Y + 1, cardx, turnover);
344 	return win;
345 }
346 
347 /*
348  * peg:
349  *	Handle all the pegging...
350  */
351 
352 static CARD		Table[14];
353 
354 static int		Tcnt;
355 
356 peg(mycrib)
357 BOOLEAN		mycrib;
358 {
359 	static CARD		ch[CINHAND], ph[CINHAND];
360 	CARD			crd;
361 	register int		i, j, k;
362 	int			l;
363 	int			cnum, pnum, sum;
364 	BOOLEAN			myturn, mego, ugo, last, played;
365 
366 	cnum = pnum = CINHAND;
367 	for (i = 0; i < CINHAND; i++) {		/* make copies of hands */
368 	    ch[i] = chand[i];
369 	    ph[i] = phand[i];
370 	}
371 	Tcnt = 0;			/* index to table of cards played */
372 	sum = 0;			/* sum of cards played */
373 	mego = ugo = FALSE;
374 	myturn = !mycrib;
375 	for (;;) {
376 	    last = TRUE;				/* enable last flag */
377 	    prtable(sum);
378 	    prhand(ph, pnum, Playwin);
379 	    if (myturn) {				/* my tyrn to play */
380 		if (!anymove(ch, cnum, sum)) {		/* if no card to play */
381 		    if (!mego && cnum) {		/* go for comp? */
382 			msg("GO.");
383 			mego = TRUE;
384 		    }
385 		    if (anymove(ph, pnum, sum))		/* can player move? */
386 			myturn = !myturn;
387 		    else {				/* give him his point */
388 			msg(quiet ? "You get one." : "You get one point.");
389 			if (chkscr(&pscore, 1))
390 			    return TRUE;
391 			sum = 0;
392 			mego = ugo = FALSE;
393 			Tcnt = 0;
394 			Hasread = FALSE;
395 		    }
396 		}
397 		else {
398 		    played = TRUE;
399 		    j = -1;
400 		    k = 0;
401 		    for (i = 0; i < cnum; i++) {	/* maximize score */
402 			l = pegscore(ch[i], Table, Tcnt, sum);
403 			if (l > k) {
404 			    k = l;
405 			    j = i;
406 			}
407 		    }
408 		    if (j < 0)				/* if nothing scores */
409 			j = cchose(ch, cnum, sum);
410 		    crd = ch[j];
411 		    remove(crd, ch, cnum--);
412 		    sum += VAL(crd.rank);
413 		    Table[Tcnt++] = crd;
414 		    if (k > 0) {
415 			addmsg(quiet ? "I get %d playing " : "I get %d points playing ", k);
416 			msgcard(crd, FALSE);
417 			endmsg();
418 			if (chkscr(&cscore, k))
419 			    return TRUE;
420 		    }
421 		    myturn = !myturn;
422 		}
423 	    }
424 	    else {
425 		if (!anymove(ph, pnum, sum)) {		/* can player move? */
426 		    if (!ugo && pnum) {			/* go for player */
427 			msg("You have a GO.");
428 			ugo = TRUE;
429 		    }
430 		    if (anymove(ch, cnum, sum))		/* can computer play? */
431 			myturn = !myturn;
432 		    else {
433 			msg(quiet ? "I get one." : "I get one point.");
434 			if (chkscr(&cscore, 1))
435 			    return TRUE;
436 			sum = 0;
437 			mego = ugo = FALSE;
438 			Tcnt = 0;
439 			Hasread = FALSE;
440 		    }
441 		}
442 		else {					/* player plays */
443 		    played = FALSE;
444 		    if (pnum == 1) {
445 			crd = ph[0];
446 			msg("You play your last card");
447 		    }
448 		    else
449 			for (;;) {
450 			    msg("Your play: ");
451 			    prhand(ph, pnum, Playwin);
452 			    crd = ph[infrom(ph, pnum, "Your play: ")];
453 			    if (sum + VAL(crd.rank) <= 31)
454 				break;
455 			    else
456 				msg("Total > 31 -- try again.");
457 			}
458 		    makeknown(&crd, 1);
459 		    remove(crd, ph, pnum--);
460 		    i = pegscore(crd, Table, Tcnt, sum);
461 		    sum += VAL(crd.rank);
462 		    Table[Tcnt++] = crd;
463 		    if (i > 0) {
464 			msg(quiet ? "You got %d" : "You got %d points", i);
465 			if (chkscr(&pscore, i))
466 			    return TRUE;
467 		    }
468 		    myturn = !myturn;
469 		}
470 	    }
471 	    if (sum >= 31) {
472 		sum = 0;
473 		mego = ugo = FALSE;
474 		Tcnt = 0;
475 		last = FALSE;				/* disable last flag */
476 		Hasread = FALSE;
477 	    }
478 	    if (!pnum && !cnum)
479 		break;					/* both done */
480 	}
481 	if (last)
482 	    if (played) {
483 		msg(quiet ? "I get one for last" : "I get one point for last");
484 		if (chkscr(&cscore, 1))
485 		    return TRUE;
486 	    }
487 	    else {
488 		msg(quiet ? "You get one for last" :
489 			    "You get one point for last");
490 		if (chkscr(&pscore, 1))
491 		    return TRUE;
492 	    }
493 	return FALSE;
494 }
495 
496 /*
497  * prtable:
498  *	Print out the table with the current score
499  */
500 prtable(score)
501 int	score;
502 {
503 	prhand(Table, Tcnt, Tablewin);
504 	mvwprintw(Tablewin, (Tcnt + 2) * 2, Tcnt + 1, "%2d", score);
505 	wrefresh(Tablewin);
506 }
507 
508 /*
509  * score:
510  *	Handle the scoring of the hands
511  */
512 score(mycrib)
513 BOOLEAN		mycrib;
514 {
515 	sorthand(crib, CINHAND);
516 	if (mycrib) {
517 	    if (plyrhand(phand, "hand"))
518 		return TRUE;
519 	    if (comphand(chand, "hand"))
520 		return TRUE;
521 	    if (comphand(crib, "crib"))
522 		return TRUE;
523 	}
524 	else {
525 	    if (comphand(chand, "hand"))
526 		return TRUE;
527 	    if (plyrhand(phand, "hand"))
528 		return TRUE;
529 	    if (plyrhand(crib, "crib"))
530 		return TRUE;
531 	}
532 	return FALSE;
533 }
534