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