Annotation of src/games/cribbage/crib.c, Revision 1.15
1.15 ! blymn 1: /* $NetBSD: crib.c,v 1.14 2001/02/05 00:28:30 christos Exp $ */
1.5 cgd 2:
3: /*-
4: * Copyright (c) 1980, 1993
5: * The Regents of the University of California. All rights reserved.
1.1 cgd 6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by the University of
18: * California, Berkeley and its contributors.
19: * 4. Neither the name of the University nor the names of its contributors
20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: */
35:
1.8 lukem 36: #include <sys/cdefs.h>
1.1 cgd 37: #ifndef lint
1.8 lukem 38: __COPYRIGHT("@(#) Copyright (c) 1980, 1993\n\
39: The Regents of the University of California. All rights reserved.\n");
1.1 cgd 40: #endif /* not lint */
41:
42: #ifndef lint
1.5 cgd 43: #if 0
44: static char sccsid[] = "@(#)crib.c 8.1 (Berkeley) 5/31/93";
45: #else
1.15 ! blymn 46: __RCSID("$NetBSD: crib.c,v 1.14 2001/02/05 00:28:30 christos Exp $");
1.5 cgd 47: #endif
1.1 cgd 48: #endif /* not lint */
49:
1.5 cgd 50: #include <curses.h>
1.9 lukem 51: #include <err.h>
1.12 jsm 52: #include <fcntl.h>
1.5 cgd 53: #include <signal.h>
54: #include <stdlib.h>
55: #include <string.h>
56: #include <unistd.h>
57:
58: #include "deck.h"
59: #include "cribbage.h"
60: #include "cribcur.h"
61: #include "pathnames.h"
1.1 cgd 62:
1.8 lukem 63: int main __P((int, char *[]));
64:
1.5 cgd 65: int
1.1 cgd 66: main(argc, argv)
1.5 cgd 67: int argc;
68: char *argv[];
1.1 cgd 69: {
1.5 cgd 70: BOOLEAN playing;
71: FILE *f;
1.1 cgd 72: int ch;
1.12 jsm 73: int fd;
74: int flags;
75:
76: f = fopen(_PATH_LOG, "a");
77: if (f == NULL)
78: warn("fopen %s", _PATH_LOG);
79: if (f != NULL && fileno(f) < 3)
80: exit(1);
81:
82: /* Revoke setgid privileges */
1.13 mycroft 83: setgid(getgid());
1.12 jsm 84:
85: /* Set close-on-exec flag on log file */
86: if (f != NULL) {
87: fd = fileno(f);
88: flags = fcntl(fd, F_GETFD);
89: if (flags < 0)
90: err(1, "fcntl F_GETFD");
91: flags |= FD_CLOEXEC;
92: if (fcntl(fd, F_SETFD, flags) == -1)
93: err(1, "fcntl F_SETFD");
94: }
1.1 cgd 95:
1.8 lukem 96: while ((ch = getopt(argc, argv, "eqr")) != -1)
1.5 cgd 97: switch (ch) {
1.1 cgd 98: case 'e':
99: explain = TRUE;
100: break;
101: case 'q':
102: quiet = TRUE;
103: break;
104: case 'r':
105: rflag = TRUE;
106: break;
107: case '?':
108: default:
109: (void) fprintf(stderr, "usage: cribbage [-eqr]\n");
110: exit(1);
111: }
112:
113: initscr();
1.5 cgd 114: (void)signal(SIGINT, rint);
1.15 ! blymn 115: cbreak();
1.1 cgd 116: noecho();
1.5 cgd 117:
1.1 cgd 118: Playwin = subwin(stdscr, PLAY_Y, PLAY_X, 0, 0);
119: Tablewin = subwin(stdscr, TABLE_Y, TABLE_X, 0, PLAY_X);
120: Compwin = subwin(stdscr, COMP_Y, COMP_X, 0, TABLE_X + PLAY_X);
121: Msgwin = subwin(stdscr, MSG_Y, MSG_X, Y_MSG_START, SCORE_X + 1);
122: leaveok(Playwin, TRUE);
123: leaveok(Tablewin, TRUE);
124: leaveok(Compwin, TRUE);
125: clearok(stdscr, FALSE);
126:
127: if (!quiet) {
1.5 cgd 128: msg("Do you need instructions for cribbage? ");
129: if (getuchar() == 'Y') {
130: endwin();
131: clear();
132: mvcur(0, COLS - 1, LINES - 1, 0);
133: fflush(stdout);
134: instructions();
135: crmode();
136: noecho();
137: clear();
138: refresh();
139: msg("For cribbage rules, use \"man cribbage\"");
140: }
1.1 cgd 141: }
142: playing = TRUE;
143: do {
1.5 cgd 144: wclrtobot(Msgwin);
145: msg(quiet ? "L or S? " : "Long (to 121) or Short (to 61)? ");
146: if (glimit == SGAME)
147: glimit = (getuchar() == 'L' ? LGAME : SGAME);
148: else
149: glimit = (getuchar() == 'S' ? SGAME : LGAME);
150: game();
151: msg("Another game? ");
152: playing = (getuchar() == 'Y');
1.1 cgd 153: } while (playing);
154:
1.12 jsm 155: if (f != NULL) {
1.1 cgd 156: (void)fprintf(f, "%s: won %5.5d, lost %5.5d\n",
1.5 cgd 157: getlogin(), cgames, pgames);
158: (void) fclose(f);
1.1 cgd 159: }
160: bye();
161: exit(0);
162: }
163:
164: /*
165: * makeboard:
166: * Print out the initial board on the screen
167: */
1.5 cgd 168: void
1.1 cgd 169: makeboard()
170: {
1.5 cgd 171: mvaddstr(SCORE_Y + 0, SCORE_X,
172: "+---------------------------------------+");
173: mvaddstr(SCORE_Y + 1, SCORE_X,
174: "| Score: 0 YOU |");
175: mvaddstr(SCORE_Y + 2, SCORE_X,
176: "| *.....:.....:.....:.....:.....:..... |");
177: mvaddstr(SCORE_Y + 3, SCORE_X,
178: "| *.....:.....:.....:.....:.....:..... |");
179: mvaddstr(SCORE_Y + 4, SCORE_X,
180: "| |");
181: mvaddstr(SCORE_Y + 5, SCORE_X,
182: "| *.....:.....:.....:.....:.....:..... |");
183: mvaddstr(SCORE_Y + 6, SCORE_X,
184: "| *.....:.....:.....:.....:.....:..... |");
185: mvaddstr(SCORE_Y + 7, SCORE_X,
186: "| Score: 0 ME |");
187: mvaddstr(SCORE_Y + 8, SCORE_X,
188: "+---------------------------------------+");
189: gamescore();
1.1 cgd 190: }
191:
192: /*
193: * gamescore:
194: * Print out the current game score
195: */
1.5 cgd 196: void
1.1 cgd 197: gamescore()
198: {
1.5 cgd 199: if (pgames || cgames) {
200: mvprintw(SCORE_Y + 1, SCORE_X + 28, "Games: %3d", pgames);
201: mvprintw(SCORE_Y + 7, SCORE_X + 28, "Games: %3d", cgames);
202: }
203: Lastscore[0] = -1;
204: Lastscore[1] = -1;
1.1 cgd 205: }
206:
207: /*
208: * game:
209: * Play one game up to glimit points. Actually, we only ASK the
210: * player what card to turn. We do a random one, anyway.
211: */
1.5 cgd 212: void
1.1 cgd 213: game()
214: {
1.8 lukem 215: int i, j;
1.5 cgd 216: BOOLEAN flag;
217: BOOLEAN compcrib;
1.1 cgd 218:
1.8 lukem 219: compcrib = FALSE;
1.1 cgd 220: makedeck(deck);
221: shuffle(deck);
222: if (gamecount == 0) {
1.5 cgd 223: flag = TRUE;
224: do {
225: if (!rflag) { /* player cuts deck */
226: msg(quiet ? "Cut for crib? " :
227: "Cut to see whose crib it is -- low card wins? ");
228: getline();
229: }
230: i = (rand() >> 4) % CARDS; /* random cut */
231: do { /* comp cuts deck */
232: j = (rand() >> 4) % CARDS;
233: } while (j == i);
234: addmsg(quiet ? "You cut " : "You cut the ");
235: msgcard(deck[i], FALSE);
236: endmsg();
237: addmsg(quiet ? "I cut " : "I cut the ");
238: msgcard(deck[j], FALSE);
239: endmsg();
240: flag = (deck[i].rank == deck[j].rank);
241: if (flag) {
242: msg(quiet ? "We tied..." :
243: "We tied and have to try again...");
244: shuffle(deck);
245: continue;
246: } else
247: compcrib = (deck[i].rank > deck[j].rank);
248: } while (flag);
1.6 phil 249: do_wait();
1.5 cgd 250: clear();
251: makeboard();
252: refresh();
253: } else {
1.6 phil 254: makeboard();
255: refresh();
1.5 cgd 256: werase(Tablewin);
257: wrefresh(Tablewin);
258: werase(Compwin);
259: wrefresh(Compwin);
260: msg("Loser (%s) gets first crib", (iwon ? "you" : "me"));
261: compcrib = !iwon;
1.1 cgd 262: }
263:
264: pscore = cscore = 0;
265: flag = TRUE;
266: do {
1.5 cgd 267: shuffle(deck);
268: flag = !playhand(compcrib);
269: compcrib = !compcrib;
1.1 cgd 270: } while (flag);
271: ++gamecount;
272: if (cscore < pscore) {
1.5 cgd 273: if (glimit - cscore > 60) {
274: msg("YOU DOUBLE SKUNKED ME!");
275: pgames += 4;
276: } else
277: if (glimit - cscore > 30) {
278: msg("YOU SKUNKED ME!");
279: pgames += 2;
280: } else {
281: msg("YOU WON!");
282: ++pgames;
283: }
284: iwon = FALSE;
285: } else {
286: if (glimit - pscore > 60) {
287: msg("I DOUBLE SKUNKED YOU!");
288: cgames += 4;
289: } else
290: if (glimit - pscore > 30) {
291: msg("I SKUNKED YOU!");
292: cgames += 2;
293: } else {
294: msg("I WON!");
295: ++cgames;
296: }
297: iwon = TRUE;
1.1 cgd 298: }
299: gamescore();
300: }
301:
302: /*
303: * playhand:
304: * Do up one hand of the game
305: */
1.5 cgd 306: int
1.1 cgd 307: playhand(mycrib)
1.5 cgd 308: BOOLEAN mycrib;
1.1 cgd 309: {
1.8 lukem 310: int deckpos;
1.1 cgd 311:
312: werase(Compwin);
1.6 phil 313: wrefresh(Compwin);
314: werase(Tablewin);
315: wrefresh(Tablewin);
1.1 cgd 316:
317: knownum = 0;
318: deckpos = deal(mycrib);
319: sorthand(chand, FULLHAND);
320: sorthand(phand, FULLHAND);
321: makeknown(chand, FULLHAND);
322: prhand(phand, FULLHAND, Playwin, FALSE);
323: discard(mycrib);
324: if (cut(mycrib, deckpos))
1.5 cgd 325: return TRUE;
1.1 cgd 326: if (peg(mycrib))
1.5 cgd 327: return TRUE;
1.1 cgd 328: werase(Tablewin);
329: wrefresh(Tablewin);
330: if (score(mycrib))
1.5 cgd 331: return TRUE;
1.1 cgd 332: return FALSE;
333: }
334:
335: /*
336: * deal cards to both players from deck
337: */
1.5 cgd 338: int
339: deal(mycrib)
340: BOOLEAN mycrib;
341: {
1.8 lukem 342: int i, j;
1.5 cgd 343:
344: for (i = j = 0; i < FULLHAND; i++) {
345: if (mycrib) {
346: phand[i] = deck[j++];
347: chand[i] = deck[j++];
348: } else {
349: chand[i] = deck[j++];
350: phand[i] = deck[j++];
351: }
1.1 cgd 352: }
1.5 cgd 353: return (j);
1.1 cgd 354: }
355:
356: /*
357: * discard:
358: * Handle players discarding into the crib...
359: * Note: we call cdiscard() after prining first message so player doesn't wait
360: */
1.5 cgd 361: void
1.1 cgd 362: discard(mycrib)
1.5 cgd 363: BOOLEAN mycrib;
1.1 cgd 364: {
1.11 jsm 365: const char *prompt;
1.5 cgd 366: CARD crd;
1.1 cgd 367:
368: prcrib(mycrib, TRUE);
369: prompt = (quiet ? "Discard --> " : "Discard a card --> ");
1.5 cgd 370: cdiscard(mycrib); /* puts best discard at end */
1.1 cgd 371: crd = phand[infrom(phand, FULLHAND, prompt)];
372: cremove(crd, phand, FULLHAND);
373: prhand(phand, FULLHAND, Playwin, FALSE);
374: crib[0] = crd;
1.5 cgd 375:
376: /* Next four lines same as last four except for cdiscard(). */
1.1 cgd 377: crd = phand[infrom(phand, FULLHAND - 1, prompt)];
378: cremove(crd, phand, FULLHAND - 1);
379: prhand(phand, FULLHAND, Playwin, FALSE);
380: crib[1] = crd;
381: crib[2] = chand[4];
382: crib[3] = chand[5];
383: chand[4].rank = chand[4].suit = chand[5].rank = chand[5].suit = EMPTY;
384: }
385:
386: /*
387: * cut:
388: * Cut the deck and set turnover. Actually, we only ASK the
389: * player what card to turn. We do a random one, anyway.
390: */
1.5 cgd 391: int
1.1 cgd 392: cut(mycrib, pos)
1.5 cgd 393: BOOLEAN mycrib;
394: int pos;
1.1 cgd 395: {
1.8 lukem 396: int i;
1.5 cgd 397: BOOLEAN win;
1.1 cgd 398:
1.5 cgd 399: win = FALSE;
1.1 cgd 400: if (mycrib) {
1.5 cgd 401: if (!rflag) { /* random cut */
402: msg(quiet ? "Cut the deck? " :
403: "How many cards down do you wish to cut the deck? ");
404: getline();
405: }
406: i = (rand() >> 4) % (CARDS - pos);
407: turnover = deck[i + pos];
408: addmsg(quiet ? "You cut " : "You cut the ");
409: msgcard(turnover, FALSE);
410: endmsg();
411: if (turnover.rank == JACK) {
412: msg("I get two for his heels");
413: win = chkscr(&cscore, 2);
414: }
415: } else {
416: i = (rand() >> 4) % (CARDS - pos) + pos;
417: turnover = deck[i];
418: addmsg(quiet ? "I cut " : "I cut the ");
419: msgcard(turnover, FALSE);
420: endmsg();
421: if (turnover.rank == JACK) {
422: msg("You get two for his heels");
423: win = chkscr(&pscore, 2);
424: }
1.1 cgd 425: }
426: makeknown(&turnover, 1);
427: prcrib(mycrib, FALSE);
1.5 cgd 428: return (win);
1.1 cgd 429: }
430:
431: /*
432: * prcrib:
433: * Print out the turnover card with crib indicator
434: */
1.5 cgd 435: void
1.1 cgd 436: prcrib(mycrib, blank)
1.5 cgd 437: BOOLEAN mycrib, blank;
1.1 cgd 438: {
1.8 lukem 439: int y, cardx;
1.1 cgd 440:
441: if (mycrib)
1.5 cgd 442: cardx = CRIB_X;
1.1 cgd 443: else
1.5 cgd 444: cardx = 0;
1.1 cgd 445:
446: mvaddstr(CRIB_Y, cardx + 1, "CRIB");
447: prcard(stdscr, CRIB_Y + 1, cardx, turnover, blank);
448:
449: if (mycrib)
1.5 cgd 450: cardx = 0;
1.1 cgd 451: else
1.5 cgd 452: cardx = CRIB_X;
1.1 cgd 453:
454: for (y = CRIB_Y; y <= CRIB_Y + 5; y++)
1.5 cgd 455: mvaddstr(y, cardx, " ");
1.6 phil 456: refresh();
1.1 cgd 457: }
458:
459: /*
460: * peg:
461: * Handle all the pegging...
462: */
1.5 cgd 463: static CARD Table[14];
464: static int Tcnt;
1.1 cgd 465:
1.5 cgd 466: int
1.1 cgd 467: peg(mycrib)
1.5 cgd 468: BOOLEAN mycrib;
1.1 cgd 469: {
1.5 cgd 470: static CARD ch[CINHAND], ph[CINHAND];
1.8 lukem 471: int i, j, k;
472: int l;
473: int cnum, pnum, sum;
474: BOOLEAN myturn, mego, ugo, last, played;
1.5 cgd 475: CARD crd;
1.1 cgd 476:
1.8 lukem 477: played = FALSE;
1.1 cgd 478: cnum = pnum = CINHAND;
1.5 cgd 479: for (i = 0; i < CINHAND; i++) { /* make copies of hands */
480: ch[i] = chand[i];
481: ph[i] = phand[i];
1.1 cgd 482: }
1.5 cgd 483: Tcnt = 0; /* index to table of cards played */
484: sum = 0; /* sum of cards played */
1.1 cgd 485: mego = ugo = FALSE;
486: myturn = !mycrib;
487: for (;;) {
1.5 cgd 488: last = TRUE; /* enable last flag */
489: prhand(ph, pnum, Playwin, FALSE);
490: prhand(ch, cnum, Compwin, TRUE);
491: prtable(sum);
492: if (myturn) { /* my tyrn to play */
493: if (!anymove(ch, cnum, sum)) { /* if no card to play */
494: if (!mego && cnum) { /* go for comp? */
495: msg("GO");
496: mego = TRUE;
497: }
498: /* can player move? */
499: if (anymove(ph, pnum, sum))
500: myturn = !myturn;
501: else { /* give him his point */
502: msg(quiet ? "You get one" :
503: "You get one point");
1.6 phil 504: do_wait();
1.5 cgd 505: if (chkscr(&pscore, 1))
506: return TRUE;
507: sum = 0;
508: mego = ugo = FALSE;
509: Tcnt = 0;
510: }
511: } else {
512: played = TRUE;
513: j = -1;
514: k = 0;
515: /* maximize score */
516: for (i = 0; i < cnum; i++) {
517: l = pegscore(ch[i], Table, Tcnt, sum);
518: if (l > k) {
519: k = l;
520: j = i;
521: }
522: }
523: if (j < 0) /* if nothing scores */
524: j = cchose(ch, cnum, sum);
525: crd = ch[j];
526: cremove(crd, ch, cnum--);
527: sum += VAL(crd.rank);
528: Table[Tcnt++] = crd;
529: if (k > 0) {
530: addmsg(quiet ? "I get %d playing " :
531: "I get %d points playing ", k);
532: msgcard(crd, FALSE);
533: endmsg();
534: if (chkscr(&cscore, k))
535: return TRUE;
536: }
537: myturn = !myturn;
538: }
539: } else {
540: if (!anymove(ph, pnum, sum)) { /* can player move? */
541: if (!ugo && pnum) { /* go for player */
542: msg("You have a GO");
543: ugo = TRUE;
544: }
545: /* can computer play? */
546: if (anymove(ch, cnum, sum))
547: myturn = !myturn;
548: else {
549: msg(quiet ? "I get one" :
550: "I get one point");
551: do_wait();
552: if (chkscr(&cscore, 1))
553: return TRUE;
554: sum = 0;
555: mego = ugo = FALSE;
556: Tcnt = 0;
557: }
558: } else { /* player plays */
559: played = FALSE;
560: if (pnum == 1) {
561: crd = ph[0];
562: msg("You play your last card");
563: } else
564: for (;;) {
565: prhand(ph,
566: pnum, Playwin, FALSE);
567: crd = ph[infrom(ph,
568: pnum, "Your play: ")];
569: if (sum + VAL(crd.rank) <= 31)
570: break;
571: else
572: msg("Total > 31 -- try again");
573: }
574: makeknown(&crd, 1);
575: cremove(crd, ph, pnum--);
576: i = pegscore(crd, Table, Tcnt, sum);
577: sum += VAL(crd.rank);
578: Table[Tcnt++] = crd;
579: if (i > 0) {
580: msg(quiet ? "You got %d" :
581: "You got %d points", i);
1.6 phil 582: if (pnum == 0)
583: do_wait();
1.5 cgd 584: if (chkscr(&pscore, i))
585: return TRUE;
586: }
587: myturn = !myturn;
1.1 cgd 588: }
589: }
1.5 cgd 590: if (sum >= 31) {
591: if (!myturn)
592: do_wait();
1.1 cgd 593: sum = 0;
594: mego = ugo = FALSE;
595: Tcnt = 0;
1.5 cgd 596: last = FALSE; /* disable last flag */
1.1 cgd 597: }
1.5 cgd 598: if (!pnum && !cnum)
599: break; /* both done */
1.1 cgd 600: }
601: prhand(ph, pnum, Playwin, FALSE);
602: prhand(ch, cnum, Compwin, TRUE);
603: prtable(sum);
1.10 veego 604: if (last) {
1.5 cgd 605: if (played) {
606: msg(quiet ? "I get one for last" :
607: "I get one point for last");
608: do_wait();
609: if (chkscr(&cscore, 1))
610: return TRUE;
611: } else {
612: msg(quiet ? "You get one for last" :
1.1 cgd 613: "You get one point for last");
1.6 phil 614: do_wait();
1.5 cgd 615: if (chkscr(&pscore, 1))
616: return TRUE;
617: }
1.10 veego 618: }
1.5 cgd 619: return (FALSE);
1.1 cgd 620: }
621:
622: /*
623: * prtable:
624: * Print out the table with the current score
625: */
1.5 cgd 626: void
1.1 cgd 627: prtable(score)
1.5 cgd 628: int score;
1.1 cgd 629: {
630: prhand(Table, Tcnt, Tablewin, FALSE);
631: mvwprintw(Tablewin, (Tcnt + 2) * 2, Tcnt + 1, "%2d", score);
632: wrefresh(Tablewin);
633: }
634:
635: /*
636: * score:
637: * Handle the scoring of the hands
638: */
1.5 cgd 639: int
1.1 cgd 640: score(mycrib)
1.5 cgd 641: BOOLEAN mycrib;
1.1 cgd 642: {
643: sorthand(crib, CINHAND);
644: if (mycrib) {
1.5 cgd 645: if (plyrhand(phand, "hand"))
646: return (TRUE);
647: if (comphand(chand, "hand"))
648: return (TRUE);
649: do_wait();
650: if (comphand(crib, "crib"))
651: return (TRUE);
1.6 phil 652: do_wait();
1.5 cgd 653: } else {
654: if (comphand(chand, "hand"))
655: return (TRUE);
656: if (plyrhand(phand, "hand"))
657: return (TRUE);
658: if (plyrhand(crib, "crib"))
659: return (TRUE);
1.1 cgd 660: }
1.5 cgd 661: return (FALSE);
1.1 cgd 662: }
CVSweb <webmaster@jp.NetBSD.org>