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