don't add an extra tab in the header (white space should already exist)
[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();
62136f2a
KA
56 Playwin = subwin(stdscr, PLAY_Y, PLAY_X, 0, SCORE_SZ);
57 Tablewin = subwin(stdscr, TABLE_Y, TABLE_X, 0, PLAY_X + SCORE_SZ);
58 Compwin = subwin(stdscr, COMP_Y, COMP_X, 0, TABLE_X + PLAY_X + SCORE_SZ);
5836528f
KA
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, "+---------------------------------------+");
608476cd 117 mvaddstr(SCORE_Y + 1, SCORE_X, "| Score: 0 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, "| *.....:.....:.....:.....:.....:..... |");
608476cd 123 mvaddstr(SCORE_Y + 7, SCORE_X, "| Score: 0 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 202 } while (flag);
7bbc756f 203 ++gamecount;
5836528f
KA
204 if (cscore < pscore) {
205 if (glimit - cscore > 60) {
206 msg("YOU DOUBLE SKUNKED ME!");
207 pgames += 4;
7bbc756f 208 }
5836528f
KA
209 else if (glimit - cscore > 30) {
210 msg("YOU SKUNKED ME!");
211 pgames += 2;
212 }
213 else {
214 msg("YOU WON!");
7bbc756f
KA
215 ++pgames;
216 }
217 iwon = FALSE;
218 }
5836528f
KA
219 else {
220 if (glimit - pscore > 60) {
221 msg("I DOUBLE SKUNKED YOU!");
222 cgames += 4;
7bbc756f 223 }
5836528f
KA
224 else if (glimit - pscore > 30) {
225 msg("I SKUNKED YOU!");
226 cgames += 2;
227 }
228 else {
229 msg("I WON!");
7bbc756f
KA
230 ++cgames;
231 }
232 iwon = TRUE;
233 }
b6b51343 234 gamescore();
7bbc756f
KA
235}
236
7bbc756f 237/*
5836528f
KA
238 * playhand:
239 * Do up one hand of the game
7bbc756f 240 */
5836528f
KA
241playhand(mycrib)
242BOOLEAN mycrib;
7bbc756f 243{
5836528f
KA
244 register int deckpos;
245 extern char Msgbuf[];
246
247 werase(Compwin);
248 wrefresh(Compwin);
62136f2a 249 move(CRIB_Y, SCORE_SZ);
5836528f
KA
250 clrtobot();
251 mvaddstr(LINES - 1, 0, Msgbuf);
7bbc756f
KA
252
253 knownum = 0;
5836528f
KA
254 deckpos = deal(mycrib);
255 sorthand(chand, FULLHAND);
256 sorthand(phand, FULLHAND);
257 makeknown(chand, FULLHAND);
5dc185f5 258 prhand(phand, FULLHAND, Playwin, FALSE);
5836528f
KA
259 discard(mycrib);
260 if (cut(mycrib, deckpos))
261 return TRUE;
262 if (peg(mycrib))
263 return TRUE;
264 werase(Tablewin);
265 wrefresh(Tablewin);
266 if (score(mycrib))
267 return TRUE;
268 return FALSE;
7bbc756f
KA
269}
270
271
272
273/*
274 * deal cards to both players from deck
275 */
276
277deal( mycrib )
278{
279 register int i, j;
280
281 j = 0;
282 for( i = 0; i < FULLHAND; i++ ) {
283 if( mycrib ) {
284 phand[i] = deck[j++];
285 chand[i] = deck[j++];
286 }
287 else {
288 chand[i] = deck[j++];
289 phand[i] = deck[j++];
290 }
291 }
292 return( j );
293}
294
7bbc756f 295/*
5836528f
KA
296 * discard:
297 * Handle players discarding into the crib...
298 * Note: we call cdiscard() after prining first message so player doesn't wait
7bbc756f 299 */
5836528f
KA
300discard(mycrib)
301BOOLEAN mycrib;
7bbc756f 302{
5836528f
KA
303 register char *prompt;
304 CARD crd;
305
f62fed8c 306 prcrib(mycrib, TRUE);
5836528f 307 prompt = (quiet ? "Discard --> " : "Discard a card --> ");
5836528f
KA
308 cdiscard(mycrib); /* puts best discard at end */
309 crd = phand[infrom(phand, FULLHAND, prompt)];
310 remove(crd, phand, FULLHAND);
5dc185f5 311 prhand(phand, FULLHAND, Playwin, FALSE);
7bbc756f 312 crib[0] = crd;
5836528f 313/* next four lines same as last four except for cdiscard() */
5836528f
KA
314 crd = phand[infrom(phand, FULLHAND - 1, prompt)];
315 remove(crd, phand, FULLHAND - 1);
5dc185f5 316 prhand(phand, FULLHAND, Playwin, FALSE);
7bbc756f
KA
317 crib[1] = crd;
318 crib[2] = chand[4];
319 crib[3] = chand[5];
5836528f 320 chand[4].rank = chand[4].suit = chand[5].rank = chand[5].suit = EMPTY;
7bbc756f
KA
321}
322
7bbc756f 323/*
5836528f 324 * cut:
d864f6e8
KA
325 * Cut the deck and set turnover. Actually, we only ASK the
326 * player what card to turn. We do a random one, anyway.
7bbc756f 327 */
5836528f
KA
328cut(mycrib, pos)
329BOOLEAN mycrib;
330int pos;
7bbc756f 331{
5836528f 332 register int i, cardx;
7bbc756f
KA
333 BOOLEAN win = FALSE;
334
5836528f 335 if (mycrib) {
d864f6e8 336 if (!rflag) { /* random cut */
5836528f
KA
337 msg(quiet ? "Cut the deck? " :
338 "How many cards down do you wish to cut the deck? ");
d864f6e8 339 getline();
7bbc756f 340 }
d864f6e8 341 i = (rand() >> 4) % (CARDS - pos);
7bbc756f 342 turnover = deck[i + pos];
5836528f
KA
343 addmsg(quiet ? "You cut " : "You cut the ");
344 msgcard(turnover, FALSE);
345 endmsg();
346 if (turnover.rank == JACK) {
347 msg("I get two for his heels.");
348 win = chkscr(&cscore,2 );
7bbc756f
KA
349 }
350 }
5836528f
KA
351 else {
352 i = (rand() >> 4) % (CARDS - pos) + pos;
7bbc756f 353 turnover = deck[i];
5836528f
KA
354 addmsg(quiet ? "I cut " : "I cut the ");
355 msgcard(turnover, FALSE);
356 endmsg();
357 if (turnover.rank == JACK) {
358 msg("You get two for his heels.");
359 win = chkscr(&pscore, 2);
7bbc756f
KA
360 }
361 }
5836528f 362 makeknown(&turnover, 1);
f62fed8c 363 prcrib(mycrib, FALSE);
5836528f 364 return win;
7bbc756f
KA
365}
366
f62fed8c
KA
367/*
368 * prcrib:
369 * Print out the turnover card with crib indicator
370 */
371prcrib(mycrib, blank)
372BOOLEAN mycrib, blank;
373{
374 register int cardx;
375
376 if (mycrib)
377 cardx = CRIB_X;
378 else
62136f2a 379 cardx = SCORE_SZ;
f62fed8c
KA
380
381 mvaddstr(CRIB_Y, cardx + 1, "CRIB");
382 prcard(stdscr, CRIB_Y + 1, cardx, turnover, blank);
383}
384
7bbc756f 385/*
5836528f
KA
386 * peg:
387 * Handle all the pegging...
7bbc756f
KA
388 */
389
5836528f
KA
390static CARD Table[14];
391
392static int Tcnt;
7bbc756f 393
5836528f
KA
394peg(mycrib)
395BOOLEAN mycrib;
7bbc756f 396{
5836528f 397 static CARD ch[CINHAND], ph[CINHAND];
7bbc756f 398 CARD crd;
5836528f 399 register int i, j, k;
fe4cdc5a
KA
400 register int l;
401 register int cnum, pnum, sum;
402 register BOOLEAN myturn, mego, ugo, last, played;
7bbc756f
KA
403
404 cnum = pnum = CINHAND;
5836528f 405 for (i = 0; i < CINHAND; i++) { /* make copies of hands */
7bbc756f
KA
406 ch[i] = chand[i];
407 ph[i] = phand[i];
408 }
5836528f 409 Tcnt = 0; /* index to table of cards played */
7bbc756f
KA
410 sum = 0; /* sum of cards played */
411 mego = ugo = FALSE;
412 myturn = !mycrib;
5836528f 413 for (;;) {
7bbc756f 414 last = TRUE; /* enable last flag */
5dc185f5
KA
415 prhand(ph, pnum, Playwin, FALSE);
416 prhand(ch, cnum, Compwin, TRUE);
fe4cdc5a 417 prtable(sum);
5836528f
KA
418 if (myturn) { /* my tyrn to play */
419 if (!anymove(ch, cnum, sum)) { /* if no card to play */
420 if (!mego && cnum) { /* go for comp? */
421 msg("GO.");
7bbc756f
KA
422 mego = TRUE;
423 }
5836528f 424 if (anymove(ph, pnum, sum)) /* can player move? */
7bbc756f 425 myturn = !myturn;
5836528f
KA
426 else { /* give him his point */
427 msg(quiet ? "You get one." : "You get one point.");
428 if (chkscr(&pscore, 1))
429 return TRUE;
7bbc756f
KA
430 sum = 0;
431 mego = ugo = FALSE;
5836528f
KA
432 Tcnt = 0;
433 Hasread = FALSE;
7bbc756f
KA
434 }
435 }
5836528f 436 else {
7bbc756f
KA
437 played = TRUE;
438 j = -1;
439 k = 0;
5836528f
KA
440 for (i = 0; i < cnum; i++) { /* maximize score */
441 l = pegscore(ch[i], Table, Tcnt, sum);
442 if (l > k) {
7bbc756f
KA
443 k = l;
444 j = i;
445 }
446 }
5836528f
KA
447 if (j < 0) /* if nothing scores */
448 j = cchose(ch, cnum, sum);
7bbc756f 449 crd = ch[j];
5836528f
KA
450 remove(crd, ch, cnum--);
451 sum += VAL(crd.rank);
452 Table[Tcnt++] = crd;
453 if (k > 0) {
86410cf9
KA
454 addmsg(quiet ? "I get %d playing " :
455 "I get %d points playing ", k);
5836528f
KA
456 msgcard(crd, FALSE);
457 endmsg();
458 if (chkscr(&cscore, k))
459 return TRUE;
7bbc756f 460 }
7bbc756f
KA
461 myturn = !myturn;
462 }
463 }
5836528f
KA
464 else {
465 if (!anymove(ph, pnum, sum)) { /* can player move? */
466 if (!ugo && pnum) { /* go for player */
467 msg("You have a GO.");
7bbc756f
KA
468 ugo = TRUE;
469 }
5836528f 470 if (anymove(ch, cnum, sum)) /* can computer play? */
7bbc756f 471 myturn = !myturn;
5836528f
KA
472 else {
473 msg(quiet ? "I get one." : "I get one point.");
474 if (chkscr(&cscore, 1))
475 return TRUE;
7bbc756f
KA
476 sum = 0;
477 mego = ugo = FALSE;
5836528f
KA
478 Tcnt = 0;
479 Hasread = FALSE;
7bbc756f
KA
480 }
481 }
5836528f 482 else { /* player plays */
7bbc756f 483 played = FALSE;
5836528f 484 if (pnum == 1) {
7bbc756f 485 crd = ph[0];
5836528f 486 msg("You play your last card");
7bbc756f 487 }
5836528f
KA
488 else
489 for (;;) {
5dc185f5 490 prhand(ph, pnum, Playwin, FALSE);
5836528f
KA
491 crd = ph[infrom(ph, pnum, "Your play: ")];
492 if (sum + VAL(crd.rank) <= 31)
7bbc756f 493 break;
5836528f
KA
494 else
495 msg("Total > 31 -- try again.");
496 }
497 makeknown(&crd, 1);
498 remove(crd, ph, pnum--);
499 i = pegscore(crd, Table, Tcnt, sum);
500 sum += VAL(crd.rank);
501 Table[Tcnt++] = crd;
502 if (i > 0) {
503 msg(quiet ? "You got %d" : "You got %d points", i);
504 if (chkscr(&pscore, i))
505 return TRUE;
7bbc756f 506 }
7bbc756f
KA
507 myturn = !myturn;
508 }
509 }
5836528f 510 if (sum >= 31) {
7bbc756f
KA
511 sum = 0;
512 mego = ugo = FALSE;
5836528f 513 Tcnt = 0;
7bbc756f 514 last = FALSE; /* disable last flag */
5836528f 515 Hasread = FALSE;
7bbc756f 516 }
5836528f
KA
517 if (!pnum && !cnum)
518 break; /* both done */
519 }
5dc185f5
KA
520 prhand(ph, pnum, Playwin, FALSE);
521 prhand(ch, cnum, Compwin, TRUE);
fe4cdc5a 522 prtable(sum);
5836528f
KA
523 if (last)
524 if (played) {
525 msg(quiet ? "I get one for last" : "I get one point for last");
526 if (chkscr(&cscore, 1))
527 return TRUE;
7bbc756f 528 }
5836528f
KA
529 else {
530 msg(quiet ? "You get one for last" :
531 "You get one point for last");
532 if (chkscr(&pscore, 1))
533 return TRUE;
7bbc756f 534 }
5836528f 535 return FALSE;
7bbc756f
KA
536}
537
7bbc756f 538/*
5836528f
KA
539 * prtable:
540 * Print out the table with the current score
7bbc756f 541 */
5836528f
KA
542prtable(score)
543int score;
544{
5dc185f5 545 prhand(Table, Tcnt, Tablewin, FALSE);
5836528f
KA
546 mvwprintw(Tablewin, (Tcnt + 2) * 2, Tcnt + 1, "%2d", score);
547 wrefresh(Tablewin);
548}
7bbc756f 549
5836528f
KA
550/*
551 * score:
552 * Handle the scoring of the hands
553 */
554score(mycrib)
555BOOLEAN mycrib;
7bbc756f 556{
5836528f
KA
557 sorthand(crib, CINHAND);
558 if (mycrib) {
559 if (plyrhand(phand, "hand"))
560 return TRUE;
561 if (comphand(chand, "hand"))
562 return TRUE;
563 if (comphand(crib, "crib"))
564 return TRUE;
7bbc756f 565 }
5836528f
KA
566 else {
567 if (comphand(chand, "hand"))
568 return TRUE;
569 if (plyrhand(phand, "hand"))
570 return TRUE;
571 if (plyrhand(crib, "crib"))
572 return TRUE;
7bbc756f 573 }
5836528f 574 return FALSE;
7bbc756f 575}