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