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