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