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