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