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