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