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