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. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#) Copyright (c) 1980, 1993 The Regents of the University of California. All rights reserved. 34 * @(#)crib.c 8.1 (Berkeley) 5/31/93 35 * $FreeBSD: src/games/cribbage/crib.c,v 1.10 1999/12/12 03:04:14 billf Exp $ 36 * $DragonFly: src/games/cribbage/crib.c,v 1.3 2005/08/03 13:31:00 eirikn Exp $ 37 */ 38 39 #include <signal.h> 40 #include <stdlib.h> 41 #include <unistd.h> 42 #include <stdio.h> 43 44 #include "cribbage.h" 45 #include "cribcur.h" 46 #include "pathnames.h" 47 48 static bool cut(bool, int); 49 static int deal(bool); 50 static void discard(bool); 51 static void game(void); 52 static void gamescore(void); 53 static void makeboard(void); 54 static bool peg(bool); 55 static bool playhand(bool); 56 static void prcrib(bool, bool); 57 static void prtable(int); 58 static bool scoreh(bool); 59 60 int 61 main(int argc, char *argv[]) 62 { 63 bool playing; 64 FILE *f; 65 int ch; 66 67 f = fopen(_PATH_LOG, "a"); 68 69 /* revoke */ 70 setgid(getgid()); 71 72 while ((ch = getopt(argc, argv, "eqr")) != -1) 73 switch (ch) { 74 case 'e': 75 explain = true; 76 break; 77 case 'q': 78 quiet = true; 79 break; 80 case 'r': 81 rflag = true; 82 break; 83 case '?': 84 default: 85 fprintf(stderr, "usage: cribbage [-eqr]\n"); 86 exit(1); 87 } 88 89 initscr(); 90 signal(SIGINT, intr); 91 crmode(); 92 noecho(); 93 94 Playwin = subwin(stdscr, PLAY_Y, PLAY_X, 0, 0); 95 Tablewin = subwin(stdscr, TABLE_Y, TABLE_X, 0, PLAY_X); 96 Compwin = subwin(stdscr, COMP_Y, COMP_X, 0, TABLE_X + PLAY_X); 97 Msgwin = subwin(stdscr, MSG_Y, MSG_X, Y_MSG_START, SCORE_X + 1); 98 leaveok(Playwin, TRUE); 99 leaveok(Tablewin, TRUE); 100 leaveok(Compwin, TRUE); 101 clearok(stdscr, FALSE); 102 103 if (!quiet) { 104 msg("Do you need instructions for cribbage? "); 105 if (getuchar() == 'Y') { 106 endwin(); 107 clear(); 108 mvcur(0, COLS - 1, LINES - 1, 0); 109 fflush(stdout); 110 instructions(); 111 crmode(); 112 noecho(); 113 clear(); 114 refresh(); 115 msg("For cribbage rules, use \"man cribbage\""); 116 } 117 } 118 playing = true; 119 do { 120 wclrtobot(Msgwin); 121 msg(quiet ? "L or S? " : "Long (to 121) or Short (to 61)? "); 122 if (glimit == SGAME) 123 glimit = (getuchar() == 'L' ? LGAME : SGAME); 124 else 125 glimit = (getuchar() == 'S' ? SGAME : LGAME); 126 game(); 127 msg("Another game? "); 128 playing = (getuchar() == 'Y'); 129 } while (playing); 130 131 if (f != NULL) { 132 fprintf(f, "%s: won %5.5d, lost %5.5d\n", 133 getlogin(), cgames, pgames); 134 fclose(f); 135 } 136 bye(); 137 if (!f) { 138 fprintf(stderr, "\ncribbage: can't open %s.\n", _PATH_LOG); 139 exit(1); 140 } 141 return(0); 142 } 143 144 /* 145 * makeboard: 146 * Print out the initial board on the screen 147 */ 148 static void 149 makeboard(void) 150 { 151 mvaddstr(SCORE_Y + 0, SCORE_X, 152 "+---------------------------------------+"); 153 mvaddstr(SCORE_Y + 1, SCORE_X, 154 "| Score: 0 YOU |"); 155 mvaddstr(SCORE_Y + 2, SCORE_X, 156 "| *.....:.....:.....:.....:.....:..... |"); 157 mvaddstr(SCORE_Y + 3, SCORE_X, 158 "| *.....:.....:.....:.....:.....:..... |"); 159 mvaddstr(SCORE_Y + 4, SCORE_X, 160 "| |"); 161 mvaddstr(SCORE_Y + 5, SCORE_X, 162 "| *.....:.....:.....:.....:.....:..... |"); 163 mvaddstr(SCORE_Y + 6, SCORE_X, 164 "| *.....:.....:.....:.....:.....:..... |"); 165 mvaddstr(SCORE_Y + 7, SCORE_X, 166 "| Score: 0 ME |"); 167 mvaddstr(SCORE_Y + 8, SCORE_X, 168 "+---------------------------------------+"); 169 gamescore(); 170 } 171 172 /* 173 * gamescore: 174 * Print out the current game score 175 */ 176 static void 177 gamescore(void) 178 { 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 static void 194 game(void) 195 { 196 int i, j; 197 bool flag, compcrib; 198 199 compcrib = false; 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 = random() % CARDS; /* random cut */ 211 do { /* comp cuts deck */ 212 j = random() % 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 static bool 284 playhand(bool mycrib) 285 { 286 int deckpos; 287 288 werase(Compwin); 289 290 knownum = 0; 291 deckpos = deal(mycrib); 292 sorthand(chand, FULLHAND); 293 sorthand(phand, FULLHAND); 294 makeknown(chand, FULLHAND); 295 prhand(phand, FULLHAND, Playwin, false); 296 discard(mycrib); 297 if (cut(mycrib, deckpos)) 298 return true; 299 if (peg(mycrib)) 300 return true; 301 werase(Tablewin); 302 wrefresh(Tablewin); 303 if (scoreh(mycrib)) 304 return true; 305 return false; 306 } 307 308 /* 309 * deal cards to both players from deck 310 */ 311 static int 312 deal(bool mycrib) 313 { 314 int i, j; 315 316 for (i = j = 0; i < FULLHAND; i++) { 317 if (mycrib) { 318 phand[i] = deck[j++]; 319 chand[i] = deck[j++]; 320 } else { 321 chand[i] = deck[j++]; 322 phand[i] = deck[j++]; 323 } 324 } 325 return (j); 326 } 327 328 /* 329 * discard: 330 * Handle players discarding into the crib... 331 * Note: we call cdiscard() after printing first message so player doesn't wait 332 */ 333 static void 334 discard(bool mycrib) 335 { 336 const char *prompt; 337 CARD crd; 338 339 prcrib(mycrib, true); 340 prompt = (quiet ? "Discard --> " : "Discard a card --> "); 341 cdiscard(mycrib); /* puts best discard at end */ 342 crd = phand[infrom(phand, FULLHAND, prompt)]; 343 cremove(crd, phand, FULLHAND); 344 prhand(phand, FULLHAND, Playwin, false); 345 crib[0] = crd; 346 347 /* Next four lines same as last four except for cdiscard(). */ 348 crd = phand[infrom(phand, FULLHAND - 1, prompt)]; 349 cremove(crd, phand, FULLHAND - 1); 350 prhand(phand, FULLHAND, Playwin, false); 351 crib[1] = crd; 352 crib[2] = chand[4]; 353 crib[3] = chand[5]; 354 chand[4].rank = chand[4].suit = chand[5].rank = chand[5].suit = EMPTY; 355 } 356 357 /* 358 * cut: 359 * Cut the deck and set turnover. Actually, we only ASK the 360 * player what card to turn. We do a random one, anyway. 361 */ 362 static bool 363 cut(bool mycrib, int pos) 364 { 365 int i; 366 bool win; 367 368 win = false; 369 if (mycrib) { 370 if (!rflag) { /* random cut */ 371 msg(quiet ? "Cut the deck? " : 372 "How many cards down do you wish to cut the deck? "); 373 getline(); 374 } 375 i = random() % (CARDS - pos); 376 turnover = deck[i + pos]; 377 addmsg(quiet ? "You cut " : "You cut the "); 378 msgcard(turnover, false); 379 endmsg(); 380 if (turnover.rank == JACK) { 381 msg("I get two for his heels"); 382 win = chkscr(&cscore, 2); 383 } 384 } else { 385 i = random() % (CARDS - pos) + pos; 386 turnover = deck[i]; 387 addmsg(quiet ? "I cut " : "I cut the "); 388 msgcard(turnover, false); 389 endmsg(); 390 if (turnover.rank == JACK) { 391 msg("You get two for his heels"); 392 win = chkscr(&pscore, 2); 393 } 394 } 395 makeknown(&turnover, 1); 396 prcrib(mycrib, false); 397 return (win); 398 } 399 400 /* 401 * prcrib: 402 * Print out the turnover card with crib indicator 403 */ 404 static void 405 prcrib(bool mycrib, bool blank) 406 { 407 int y, cardx; 408 409 if (mycrib) 410 cardx = CRIB_X; 411 else 412 cardx = 0; 413 414 mvaddstr(CRIB_Y, cardx + 1, "CRIB"); 415 prcard(stdscr, CRIB_Y + 1, cardx, turnover, blank); 416 417 if (mycrib) 418 cardx = 0; 419 else 420 cardx = CRIB_X; 421 422 for (y = CRIB_Y; y <= CRIB_Y + 5; y++) 423 mvaddstr(y, cardx, " "); 424 } 425 426 /* 427 * peg: 428 * Handle all the pegging... 429 */ 430 static CARD Table[14]; 431 static int Tcnt; 432 433 static bool 434 peg(bool mycrib) 435 { 436 static CARD ch[CINHAND], ph[CINHAND]; 437 int i, j, k; 438 int l; 439 int cnum, pnum, sum; 440 bool myturn, mego, ugo, last, played; 441 CARD crd; 442 443 cnum = pnum = CINHAND; 444 for (i = 0; i < CINHAND; i++) { /* make copies of hands */ 445 ch[i] = chand[i]; 446 ph[i] = phand[i]; 447 } 448 Tcnt = 0; /* index to table of cards played */ 449 sum = 0; /* sum of cards played */ 450 played = mego = ugo = false; 451 myturn = !mycrib; 452 for (;;) { 453 last = true; /* enable last flag */ 454 prhand(ph, pnum, Playwin, false); 455 prhand(ch, cnum, Compwin, true); 456 prtable(sum); 457 if (myturn) { /* my tyrn to play */ 458 if (!anymove(ch, cnum, sum)) { /* if no card to play */ 459 if (!mego && cnum) { /* go for comp? */ 460 msg("GO"); 461 mego = true; 462 } 463 /* can player move? */ 464 if (anymove(ph, pnum, sum)) 465 myturn = !myturn; 466 else { /* give him his point */ 467 msg(quiet ? "You get one" : 468 "You get one point"); 469 if (chkscr(&pscore, 1)) 470 return (true); 471 sum = 0; 472 mego = ugo = false; 473 Tcnt = 0; 474 } 475 } else { 476 played = true; 477 j = -1; 478 k = 0; 479 /* maximize score */ 480 for (i = 0; i < cnum; i++) { 481 l = pegscore(ch[i], Table, Tcnt, sum); 482 if (l > k) { 483 k = l; 484 j = i; 485 } 486 } 487 if (j < 0) /* if nothing scores */ 488 j = cchose(ch, cnum, sum); 489 crd = ch[j]; 490 cremove(crd, ch, cnum--); 491 sum += VAL(crd.rank); 492 Table[Tcnt++] = crd; 493 if (k > 0) { 494 addmsg(quiet ? "I get %d playing " : 495 "I get %d points playing ", k); 496 msgcard(crd, false); 497 endmsg(); 498 if (chkscr(&cscore, k)) 499 return (true); 500 } 501 myturn = !myturn; 502 } 503 } else { 504 if (!anymove(ph, pnum, sum)) { /* can player move? */ 505 if (!ugo && pnum) { /* go for player */ 506 msg("You have a GO"); 507 ugo = true; 508 } 509 /* can computer play? */ 510 if (anymove(ch, cnum, sum)) 511 myturn = !myturn; 512 else { 513 msg(quiet ? "I get one" : 514 "I get one point"); 515 do_wait(); 516 if (chkscr(&cscore, 1)) 517 return (true); 518 sum = 0; 519 mego = ugo = false; 520 Tcnt = 0; 521 } 522 } else { /* player plays */ 523 played = false; 524 if (pnum == 1) { 525 crd = ph[0]; 526 msg("You play your last card"); 527 } else 528 for (;;) { 529 prhand(ph, 530 pnum, Playwin, false); 531 crd = ph[infrom(ph, 532 pnum, "Your play: ")]; 533 if (sum + VAL(crd.rank) <= 31) 534 break; 535 else 536 msg("Total > 31 -- try again"); 537 } 538 makeknown(&crd, 1); 539 cremove(crd, ph, pnum--); 540 i = pegscore(crd, Table, Tcnt, sum); 541 sum += VAL(crd.rank); 542 Table[Tcnt++] = crd; 543 if (i > 0) { 544 msg(quiet ? "You got %d" : 545 "You got %d points", i); 546 if (chkscr(&pscore, i)) 547 return (true); 548 } 549 myturn = !myturn; 550 } 551 } 552 if (sum >= 31) { 553 if (!myturn) 554 do_wait(); 555 sum = 0; 556 mego = ugo = false; 557 Tcnt = 0; 558 last = false; /* disable last flag */ 559 } 560 if (!pnum && !cnum) 561 break; /* both done */ 562 } 563 prhand(ph, pnum, Playwin, false); 564 prhand(ch, cnum, Compwin, true); 565 prtable(sum); 566 if (last) { 567 if (played) { 568 msg(quiet ? "I get one for last" : 569 "I get one point for last"); 570 do_wait(); 571 if (chkscr(&cscore, 1)) 572 return (true); 573 } else { 574 msg(quiet ? "You get one for last" : 575 "You get one point for last"); 576 if (chkscr(&pscore, 1)) 577 return (true); 578 } 579 } 580 return (false); 581 } 582 583 /* 584 * prtable: 585 * Print out the table with the current score 586 */ 587 static void 588 prtable(int score) 589 { 590 prhand(Table, Tcnt, Tablewin, false); 591 mvwprintw(Tablewin, (Tcnt + 2) * 2, Tcnt + 1, "%2d", score); 592 wrefresh(Tablewin); 593 } 594 595 /* 596 * scoreh: 597 * Handle the scoring of the hands 598 */ 599 static bool 600 scoreh(bool mycrib) 601 { 602 sorthand(crib, CINHAND); 603 if (mycrib) { 604 if (plyrhand(phand, "hand")) 605 return (true); 606 if (comphand(chand, "hand")) 607 return (true); 608 do_wait(); 609 if (comphand(crib, "crib")) 610 return (true); 611 } else { 612 if (comphand(chand, "hand")) 613 return (true); 614 if (plyrhand(phand, "hand")) 615 return (true); 616 if (plyrhand(crib, "crib")) 617 return (true); 618 } 619 return (false); 620 } 621