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