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 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 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 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 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 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 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 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 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 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 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 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 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