crib.c revision 1.2 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
35 char 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
41 static 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 <unistd.h>
47 # include "deck.h"
48 # include "cribbage.h"
49 # include "cribcur.h"
50 # include "pathnames.h"
51
52 main(argc, argv)
53 int argc;
54 char *argv[];
55 {
56 extern char *optarg;
57 extern int optind;
58 register char *p;
59 int ch;
60 BOOLEAN playing;
61 char *s; /* for reading arguments */
62 FILE *f;
63 FILE *fopen();
64 char *getline();
65 void rint();
66
67 while ((ch = getopt(argc, argv, "eqr")) != EOF)
68 switch(ch) {
69 case 'e':
70 explain = TRUE;
71 break;
72 case 'q':
73 quiet = TRUE;
74 break;
75 case 'r':
76 rflag = TRUE;
77 break;
78 case '?':
79 default:
80 (void) fprintf(stderr, "usage: cribbage [-eqr]\n");
81 exit(1);
82 }
83
84 initscr();
85 signal(SIGINT, rint);
86 crmode();
87 noecho();
88 Playwin = subwin(stdscr, PLAY_Y, PLAY_X, 0, 0);
89 Tablewin = subwin(stdscr, TABLE_Y, TABLE_X, 0, PLAY_X);
90 Compwin = subwin(stdscr, COMP_Y, COMP_X, 0, TABLE_X + PLAY_X);
91 Msgwin = subwin(stdscr, MSG_Y, MSG_X, Y_MSG_START, SCORE_X + 1);
92 leaveok(Playwin, TRUE);
93 leaveok(Tablewin, TRUE);
94 leaveok(Compwin, TRUE);
95 clearok(stdscr, FALSE);
96
97 if (!quiet) {
98 msg("Do you need instructions for cribbage? ");
99 if (getuchar() == 'Y') {
100 endwin();
101 clear();
102 mvcur(0, COLS - 1, LINES - 1, 0);
103 fflush(stdout);
104 instructions();
105 crmode();
106 noecho();
107 clear();
108 refresh();
109 msg("For the rules of this program, do \"man cribbage\"");
110 }
111 }
112 playing = TRUE;
113 do {
114 wclrtobot(Msgwin);
115 msg(quiet ? "L or S? " : "Long (to 121) or Short (to 61)? ");
116 if (glimit == SGAME)
117 glimit = (getuchar() == 'L' ? LGAME : SGAME);
118 else
119 glimit = (getuchar() == 'S' ? SGAME : LGAME);
120 game();
121 msg("Another game? ");
122 playing = (getuchar() == 'Y');
123 } while (playing);
124
125 if (f = fopen(_PATH_LOG, "a")) {
126 (void)fprintf(f, "%s: won %5.5d, lost %5.5d\n",
127 getlogin(), cgames, pgames);
128 (void)fclose(f);
129 }
130 bye();
131 if (!f) {
132 (void)fprintf(stderr, "\ncribbage: can't open %s.\n",
133 _PATH_LOG);
134 exit(1);
135 }
136 exit(0);
137 }
138
139 /*
140 * makeboard:
141 * Print out the initial board on the screen
142 */
143 makeboard()
144 {
145 mvaddstr(SCORE_Y + 0, SCORE_X, "+---------------------------------------+");
146 mvaddstr(SCORE_Y + 1, SCORE_X, "| Score: 0 YOU |");
147 mvaddstr(SCORE_Y + 2, SCORE_X, "| *.....:.....:.....:.....:.....:..... |");
148 mvaddstr(SCORE_Y + 3, SCORE_X, "| *.....:.....:.....:.....:.....:..... |");
149 mvaddstr(SCORE_Y + 4, SCORE_X, "| |");
150 mvaddstr(SCORE_Y + 5, SCORE_X, "| *.....:.....:.....:.....:.....:..... |");
151 mvaddstr(SCORE_Y + 6, SCORE_X, "| *.....:.....:.....:.....:.....:..... |");
152 mvaddstr(SCORE_Y + 7, SCORE_X, "| Score: 0 ME |");
153 mvaddstr(SCORE_Y + 8, SCORE_X, "+---------------------------------------+");
154 gamescore();
155 }
156
157 /*
158 * gamescore:
159 * Print out the current game score
160 */
161 gamescore()
162 {
163 extern int Lastscore[];
164
165 if (pgames || cgames) {
166 mvprintw(SCORE_Y + 1, SCORE_X + 28, "Games: %3d", pgames);
167 mvprintw(SCORE_Y + 7, SCORE_X + 28, "Games: %3d", cgames);
168 }
169 Lastscore[0] = -1;
170 Lastscore[1] = -1;
171 }
172
173 /*
174 * game:
175 * Play one game up to glimit points. Actually, we only ASK the
176 * player what card to turn. We do a random one, anyway.
177 */
178 game()
179 {
180 register int i, j;
181 BOOLEAN flag;
182 BOOLEAN compcrib;
183 char *getline();
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 */
272 playhand(mycrib)
273 BOOLEAN 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
304 deal( 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 */
327 discard(mycrib)
328 BOOLEAN 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 */
355 cut(mycrib, pos)
356 BOOLEAN mycrib;
357 int pos;
358 {
359 register int i, cardx;
360 BOOLEAN win = FALSE;
361 char *getline();
362
363 if (mycrib) {
364 if (!rflag) { /* random cut */
365 msg(quiet ? "Cut the deck? " :
366 "How many cards down do you wish to cut the deck? ");
367 getline();
368 }
369 i = (rand() >> 4) % (CARDS - pos);
370 turnover = deck[i + pos];
371 addmsg(quiet ? "You cut " : "You cut the ");
372 msgcard(turnover, FALSE);
373 endmsg();
374 if (turnover.rank == JACK) {
375 msg("I get two for his heels");
376 win = chkscr(&cscore,2 );
377 }
378 }
379 else {
380 i = (rand() >> 4) % (CARDS - pos) + pos;
381 turnover = deck[i];
382 addmsg(quiet ? "I cut " : "I cut the ");
383 msgcard(turnover, FALSE);
384 endmsg();
385 if (turnover.rank == JACK) {
386 msg("You get two for his heels");
387 win = chkscr(&pscore, 2);
388 }
389 }
390 makeknown(&turnover, 1);
391 prcrib(mycrib, FALSE);
392 return win;
393 }
394
395 /*
396 * prcrib:
397 * Print out the turnover card with crib indicator
398 */
399 prcrib(mycrib, blank)
400 BOOLEAN mycrib, blank;
401 {
402 register int y, cardx;
403
404 if (mycrib)
405 cardx = CRIB_X;
406 else
407 cardx = 0;
408
409 mvaddstr(CRIB_Y, cardx + 1, "CRIB");
410 prcard(stdscr, CRIB_Y + 1, cardx, turnover, blank);
411
412 if (mycrib)
413 cardx = 0;
414 else
415 cardx = CRIB_X;
416
417 for (y = CRIB_Y; y <= CRIB_Y + 5; y++)
418 mvaddstr(y, cardx, " ");
419 }
420
421 /*
422 * peg:
423 * Handle all the pegging...
424 */
425
426 static CARD Table[14];
427
428 static int Tcnt;
429
430 peg(mycrib)
431 BOOLEAN mycrib;
432 {
433 static CARD ch[CINHAND], ph[CINHAND];
434 CARD crd;
435 register int i, j, k;
436 register int l;
437 register int cnum, pnum, sum;
438 register BOOLEAN myturn, mego, ugo, last, played;
439
440 cnum = pnum = CINHAND;
441 for (i = 0; i < CINHAND; i++) { /* make copies of hands */
442 ch[i] = chand[i];
443 ph[i] = phand[i];
444 }
445 Tcnt = 0; /* index to table of cards played */
446 sum = 0; /* sum of cards played */
447 mego = ugo = FALSE;
448 myturn = !mycrib;
449 for (;;) {
450 last = TRUE; /* enable last flag */
451 prhand(ph, pnum, Playwin, FALSE);
452 prhand(ch, cnum, Compwin, TRUE);
453 prtable(sum);
454 if (myturn) { /* my tyrn to play */
455 if (!anymove(ch, cnum, sum)) { /* if no card to play */
456 if (!mego && cnum) { /* go for comp? */
457 msg("GO");
458 mego = TRUE;
459 }
460 if (anymove(ph, pnum, sum)) /* can player move? */
461 myturn = !myturn;
462 else { /* give him his point */
463 msg(quiet ? "You get one" : "You get one point");
464 if (chkscr(&pscore, 1))
465 return TRUE;
466 sum = 0;
467 mego = ugo = FALSE;
468 Tcnt = 0;
469 }
470 }
471 else {
472 played = TRUE;
473 j = -1;
474 k = 0;
475 for (i = 0; i < cnum; i++) { /* maximize score */
476 l = pegscore(ch[i], Table, Tcnt, sum);
477 if (l > k) {
478 k = l;
479 j = i;
480 }
481 }
482 if (j < 0) /* if nothing scores */
483 j = cchose(ch, cnum, sum);
484 crd = ch[j];
485 cremove(crd, ch, cnum--);
486 sum += VAL(crd.rank);
487 Table[Tcnt++] = crd;
488 if (k > 0) {
489 addmsg(quiet ? "I get %d playing " :
490 "I get %d points playing ", k);
491 msgcard(crd, FALSE);
492 endmsg();
493 if (chkscr(&cscore, k))
494 return TRUE;
495 }
496 myturn = !myturn;
497 }
498 }
499 else {
500 if (!anymove(ph, pnum, sum)) { /* can player move? */
501 if (!ugo && pnum) { /* go for player */
502 msg("You have a GO");
503 ugo = TRUE;
504 }
505 if (anymove(ch, cnum, sum)) /* can computer play? */
506 myturn = !myturn;
507 else {
508 msg(quiet ? "I get one" : "I get one point");
509 do_wait();
510 if (chkscr(&cscore, 1))
511 return TRUE;
512 sum = 0;
513 mego = ugo = FALSE;
514 Tcnt = 0;
515 }
516 }
517 else { /* player plays */
518 played = FALSE;
519 if (pnum == 1) {
520 crd = ph[0];
521 msg("You play your last card");
522 }
523 else
524 for (;;) {
525 prhand(ph, pnum, Playwin, FALSE);
526 crd = ph[infrom(ph, pnum, "Your play: ")];
527 if (sum + VAL(crd.rank) <= 31)
528 break;
529 else
530 msg("Total > 31 -- try again");
531 }
532 makeknown(&crd, 1);
533 cremove(crd, ph, pnum--);
534 i = pegscore(crd, Table, Tcnt, sum);
535 sum += VAL(crd.rank);
536 Table[Tcnt++] = crd;
537 if (i > 0) {
538 msg(quiet ? "You got %d" : "You got %d points", i);
539 if (chkscr(&pscore, i))
540 return TRUE;
541 }
542 myturn = !myturn;
543 }
544 }
545 if (sum >= 31) {
546 if (!myturn)
547 do_wait();
548 sum = 0;
549 mego = ugo = FALSE;
550 Tcnt = 0;
551 last = FALSE; /* disable last flag */
552 }
553 if (!pnum && !cnum)
554 break; /* both done */
555 }
556 prhand(ph, pnum, Playwin, FALSE);
557 prhand(ch, cnum, Compwin, TRUE);
558 prtable(sum);
559 if (last)
560 if (played) {
561 msg(quiet ? "I get one for last" : "I get one point for last");
562 do_wait();
563 if (chkscr(&cscore, 1))
564 return TRUE;
565 }
566 else {
567 msg(quiet ? "You get one for last" :
568 "You get one point for last");
569 if (chkscr(&pscore, 1))
570 return TRUE;
571 }
572 return FALSE;
573 }
574
575 /*
576 * prtable:
577 * Print out the table with the current score
578 */
579 prtable(score)
580 int score;
581 {
582 prhand(Table, Tcnt, Tablewin, FALSE);
583 mvwprintw(Tablewin, (Tcnt + 2) * 2, Tcnt + 1, "%2d", score);
584 wrefresh(Tablewin);
585 }
586
587 /*
588 * score:
589 * Handle the scoring of the hands
590 */
591 score(mycrib)
592 BOOLEAN mycrib;
593 {
594 sorthand(crib, CINHAND);
595 if (mycrib) {
596 if (plyrhand(phand, "hand"))
597 return TRUE;
598 if (comphand(chand, "hand"))
599 return TRUE;
600 do_wait();
601 if (comphand(crib, "crib"))
602 return TRUE;
603 }
604 else {
605 if (comphand(chand, "hand"))
606 return TRUE;
607 if (plyrhand(phand, "hand"))
608 return TRUE;
609 if (plyrhand(crib, "crib"))
610 return TRUE;
611 }
612 return FALSE;
613 }
614