(linenum→info "unix/slp.c:2238")

bsd-games/2.17/cribbage/crib.c

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