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