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