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