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