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