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