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