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

bsd-games/2.17/mille/move.c

    1: /*      $NetBSD: move.c,v 1.15 2004/11/05 21:30:32 dsl Exp $ */
    2: 
    3: /*
    4:  * Copyright (c) 1983, 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: #if 0
   35: static char sccsid[] = "@(#)move.c      8.1 (Berkeley) 5/31/93";
   36: #else
   37: __RCSID("$NetBSD: move.c,v 1.15 2004/11/05 21:30:32 dsl Exp $");
   38: #endif
   39: #endif /* not lint */
   40: 
   41: #include <termios.h>
   42: 
   43: #ifdef DEBUG
   44: #include <sys/param.h>
   45: #endif
   46: 
   47: #include        "mille.h"
   48: #ifndef unctrl
   49: #include        "unctrl.h"
   50: #endif
   51: 
   52: /*
   53:  * @(#)move.c   1.2 (Berkeley) 3/28/83
   54:  */
   55: 
   56: #undef  CTRL
   57: #define CTRL(c)         (c - 'A' + 1)
   58: 
   59: void
   60: domove()
   61: {
   62:         PLAY   *pp;
   63:         int    i, j;
   64:         bool   goodplay;
   65: 
   66:         pp = &Player[Play];
   67:         for (i = 0, j = 0; i < HAND_SZ; i++)
   68:                 if (pp->hand[i] != -1)
   69:                         j++;
   70:         if (!j) {
   71:                 nextplay();
   72:                 return;
   73:         }
   74:         if (Play == PLAYER)
   75:                 getmove();
   76:         else
   77:                 calcmove();
   78:         Next = FALSE;
   79:         goodplay = TRUE;
   80:         switch (Movetype) {
   81:           case M_DISCARD:
   82:                 if (haspicked(pp)) {
   83:                         if (pp->hand[Card_no] == C_INIT)
   84:                                 if (Card_no == 6)
   85:                                         Finished = TRUE;
   86:                                 else
   87:                                         error("no card there");
   88:                         else {
   89:                                 if (is_safety(pp->hand[Card_no])) {
   90:                                         error("discard a safety?");
   91:                                         goodplay = FALSE;
   92:                                         break;
   93:                                 }
   94:                                 Discard = pp->hand[Card_no];
   95:                                 pp->hand[Card_no] = C_INIT;
   96:                                 Next = TRUE;
   97:                                 if (Play == PLAYER)
   98:                                         account(Discard);
   99:                         }
  100:                 }
  101:                 else
  102:                         error("must pick first");
  103:                 break;
  104:           case M_PLAY:
  105:                 goodplay = playcard(pp);
  106:                 break;
  107:           case M_DRAW:
  108:                 Card_no = 0;
  109:                 if (Topcard <= Deck)
  110:                         error("no more cards");
  111:                 else if (haspicked(pp))
  112:                         error("already picked");
  113:                 else {
  114:                         pp->hand[0] = *--Topcard;
  115: #ifdef DEBUG
  116:                         if (Debug)
  117:                                 fprintf(outf, "DOMOVE: Draw %s\n", C_name[*Topcard]);
  118: #endif
  119: acc:
  120:                         if (Play == COMP) {
  121:                                 account(*Topcard);
  122:                                 if (is_safety(*Topcard))
  123:                                         pp->safety[*Topcard-S_CONV] = S_IN_HAND;
  124:                         }
  125:                         if (pp->hand[1] == C_INIT && Topcard > Deck) {
  126:                                 Card_no = 1;
  127:                                 pp->hand[1] = *--Topcard;
  128: #ifdef DEBUG
  129:                                 if (Debug)
  130:                                         fprintf(outf, "DOMOVE: Draw %s\n", C_name[*Topcard]);
  131: #endif
  132:                                 goto acc;
  133:                         }
  134:                         pp->new_battle = FALSE;
  135:                         pp->new_speed = FALSE;
  136:                 }
  137:                 break;
  138: 
  139:           case M_ORDER:
  140:                 break;
  141:         }
  142:         /*
  143:          * move blank card to top by one of two methods.  If the
  144:          * computer's hand was sorted, the randomness for picking
  145:          * between equally valued cards would be lost
  146:          */
  147:         if (Order && Movetype != M_DRAW && goodplay && pp == &Player[PLAYER])
  148:                 sort(pp->hand);
  149:         else
  150:                 for (i = 1; i < HAND_SZ; i++)
  151:                         if (pp->hand[i] == C_INIT) {
  152:                                 for (j = 0; pp->hand[j] == C_INIT; j++)
  153:                                         if (j >= HAND_SZ) {
  154:                                                 j = 0;
  155:                                                 break;
  156:                                         }
  157:                                 pp->hand[i] = pp->hand[j];
  158:                                 pp->hand[j] = C_INIT;
  159:                         }
  160:         if (Topcard <= Deck)
  161:                 check_go();
  162:         if (Next)
  163:                 nextplay();
  164: }
  165: 
  166: /*
  167:  *      Check and see if either side can go.  If they cannot,
  168:  * the game is over
  169:  */
  170: void
  171: check_go()
  172: {
  173:         CARD   card;
  174:         PLAY   *pp, *op;
  175:         int    i;
  176: 
  177:         for (pp = Player; pp < &Player[2]; pp++) {
  178:                 op = (pp == &Player[COMP] ? &Player[PLAYER] : &Player[COMP]);
  179:                 for (i = 0; i < HAND_SZ; i++) {
  180:                         card = pp->hand[i];
  181:                         if (is_safety(card) || canplay(pp, op, card)) {
  182: #ifdef DEBUG
  183:                                 if (Debug) {
  184:                                         fprintf(outf, "CHECK_GO: can play %s (%d), ", C_name[card], card);
  185:                                         fprintf(outf, "is_safety(card) = %d, ", is_safety(card));
  186:                                         fprintf(outf, "canplay(pp, op, card) = %d\n", canplay(pp, op, card));
  187:                                 }
  188: #endif
  189:                                 return;
  190:                         }
  191: #ifdef DEBUG
  192:                         else if (Debug)
  193:                                 fprintf(outf, "CHECK_GO: cannot play %s\n",
  194:                                     C_name[card]);
  195: #endif
  196:                 }
  197:         }
  198:         Finished = TRUE;
  199: }
  200: 
  201: int
  202: playcard(pp)
  203:         PLAY   *pp;
  204: {
  205:         int    v;
  206:         CARD   card;
  207: 
  208:         /*
  209:          * check and see if player has picked
  210:          */
  211:         switch (pp->hand[Card_no]) {
  212:           default:
  213:                 if (!haspicked(pp))
  214: mustpick:
  215:                         return error("must pick first");
  216:           case C_GAS_SAFE:     case C_SPARE_SAFE:
  217:           case C_DRIVE_SAFE:   case C_RIGHT_WAY:
  218:                 break;
  219:         }
  220: 
  221:         card = pp->hand[Card_no];
  222: #ifdef DEBUG
  223:         if (Debug)
  224:                 fprintf(outf, "PLAYCARD: Card = %s\n", C_name[card]);
  225: #endif
  226:         Next = FALSE;
  227:         switch (card) {
  228:           case C_200:
  229:                 if (pp->nummiles[C_200] == 2)
  230:                         return error("only two 200's per hand");
  231:           case C_100:  case C_75:
  232:                 if (pp->speed == C_LIMIT)
  233:                         return error("limit of 50");
  234:           case C_50:
  235:                 if (pp->mileage + Value[card] > End)
  236:                         return error("puts you over %d", End);
  237:           case C_25:
  238:                 if (!pp->can_go)
  239:                         return error("cannot move now");
  240:                 pp->nummiles[card]++;
  241:                 v = Value[card];
  242:                 pp->total += v;
  243:                 pp->hand_tot += v;
  244:                 if ((pp->mileage += v) == End)
  245:                         check_ext(FALSE);
  246:                 break;
  247: 
  248:           case C_GAS:  case C_SPARE:    case C_REPAIRS:
  249:                 if (pp->battle != opposite(card))
  250:                         return error("can't play \"%s\"", C_name[card]);
  251:                 pp->battle = card;
  252:                 if (pp->safety[S_RIGHT_WAY] == S_PLAYED)
  253:                         pp->can_go = TRUE;
  254:                 break;
  255: 
  256:           case C_GO:
  257:                 if (pp->battle != C_INIT && pp->battle != C_STOP
  258:                     && !is_repair(pp->battle))
  259:                         return error("cannot play \"Go\" on a \"%s\"",
  260:                             C_name[pp->battle]);
  261:                 pp->battle = C_GO;
  262:                 pp->can_go = TRUE;
  263:                 break;
  264: 
  265:           case C_END_LIMIT:
  266:                 if (pp->speed != C_LIMIT)
  267:                         return error("not limited");
  268:                 pp->speed = C_END_LIMIT;
  269:                 break;
  270: 
  271:           case C_EMPTY:        case C_FLAT:   case C_CRASH:
  272:           case C_STOP:
  273:                 pp = &Player[other(Play)];
  274:                 if (!pp->can_go)
  275:                         return error("opponent cannot go");
  276:                 else if (pp->safety[safety(card) - S_CONV] == S_PLAYED)
  277: protected:
  278:                         return error("opponent is protected");
  279:                 pp->battle = card;
  280:                 pp->new_battle = TRUE;
  281:                 pp->can_go = FALSE;
  282:                 pp = &Player[Play];
  283:                 break;
  284: 
  285:           case C_LIMIT:
  286:                 pp = &Player[other(Play)];
  287:                 if (pp->speed == C_LIMIT)
  288:                         return error("opponent has limit");
  289:                 if (pp->safety[S_RIGHT_WAY] == S_PLAYED)
  290:                         goto protected;
  291:                 pp->speed = C_LIMIT;
  292:                 pp->new_speed = TRUE;
  293:                 pp = &Player[Play];
  294:                 break;
  295: 
  296:           case C_GAS_SAFE:     case C_SPARE_SAFE:
  297:           case C_DRIVE_SAFE:   case C_RIGHT_WAY:
  298:                 if (pp->battle == opposite(card)
  299:                     || (card == C_RIGHT_WAY && pp->speed == C_LIMIT)) {
  300:                         if (!(card == C_RIGHT_WAY && !is_repair(pp->battle))) {
  301:                                 pp->battle = C_GO;
  302:                                 pp->can_go = TRUE;
  303:                         }
  304:                         if (card == C_RIGHT_WAY && pp->speed == C_LIMIT)
  305:                                 pp->speed = C_INIT;
  306:                         if (pp->new_battle
  307:                             || (pp->new_speed && card == C_RIGHT_WAY)) {
  308:                                 pp->coups[card - S_CONV] = TRUE;
  309:                                 pp->total += SC_COUP;
  310:                                 pp->hand_tot += SC_COUP;
  311:                                 pp->coupscore += SC_COUP;
  312:                         }
  313:                 }
  314:                 /*
  315:                  * if not coup, must pick first
  316:                  */
  317:                 else if (pp->hand[0] == C_INIT && Topcard > Deck)
  318:                         goto mustpick;
  319:                 pp->safety[card - S_CONV] = S_PLAYED;
  320:                 pp->total += SC_SAFETY;
  321:                 pp->hand_tot += SC_SAFETY;
  322:                 if ((pp->safescore += SC_SAFETY) == NUM_SAFE * SC_SAFETY) {
  323:                         pp->total += SC_ALL_SAFE;
  324:                         pp->hand_tot += SC_ALL_SAFE;
  325:                 }
  326:                 if (card == C_RIGHT_WAY) {
  327:                         if (pp->speed == C_LIMIT)
  328:                                 pp->speed = C_INIT;
  329:                         if (pp->battle == C_STOP || pp->battle == C_INIT) {
  330:                                 pp->can_go = TRUE;
  331:                                 pp->battle = C_INIT;
  332:                         }
  333:                         if (!pp->can_go && is_repair(pp->battle))
  334:                                 pp->can_go = TRUE;
  335:                 }
  336:                 Next = -1;
  337:                 break;
  338: 
  339:           case C_INIT:
  340:                 error("no card there");
  341:                 Next = -1;
  342:                 break;
  343:         }
  344:         if (pp == &Player[PLAYER])
  345:                 account(card);
  346:         pp->hand[Card_no] = C_INIT;
  347:         Next = (Next == (bool)-1 ? FALSE : TRUE);
  348:         return TRUE;
  349: }
  350: 
  351: void
  352: getmove()
  353: {
  354:         char   c;
  355: #ifdef EXTRAP
  356:         static bool    last_ex = FALSE;   /* set if last command was E */
  357: 
  358:         if (last_ex) {
  359:                 undoex();
  360:                 prboard();
  361:                 last_ex = FALSE;
  362:         }
  363: #endif
  364:         for (;;) {
  365:                 prompt(MOVEPROMPT);
  366:                 leaveok(Board, FALSE);
  367:                 refresh();
  368:                 while ((c = readch()) == killchar() || c == erasechar())
  369:                         continue;
  370:                 if (islower((unsigned char)c))
  371:                         c = toupper((unsigned char)c);
  372:                 if (isprint((unsigned char)c) && !isspace((unsigned char)c)) {
  373:                         addch(c);
  374:                         refresh();
  375:                 }
  376:                 switch (c) {
  377:                   case 'P':           /* Pick */
  378:                         Movetype = M_DRAW;
  379:                         goto ret;
  380:                   case 'U':           /* Use Card */
  381:                   case 'D':           /* Discard Card */
  382:                         if ((Card_no = getcard()) < 0)
  383:                                 break;
  384:                         Movetype = (c == 'U' ? M_PLAY : M_DISCARD);
  385:                         goto ret;
  386:                   case 'O':           /* Order */
  387:                         Order = !Order;
  388:                         if (Window == W_SMALL) {
  389:                                 if (!Order)
  390:                                         mvwaddstr(Score, 12, 21,
  391:                                                   "o: order hand");
  392:                                 else
  393:                                         mvwaddstr(Score, 12, 21,
  394:                                                   "o: stop ordering");
  395:                                 wclrtoeol(Score);
  396:                         }
  397:                         Movetype = M_ORDER;
  398:                         goto ret;
  399:                   case 'Q':           /* Quit */
  400:                         rub(0);              /* Same as a rubout */
  401:                         break;
  402:                   case 'W':           /* Window toggle */
  403:                         Window = nextwin(Window);
  404:                         newscore();
  405:                         prscore(TRUE);
  406:                         wrefresh(Score);
  407:                         break;
  408:                   case 'R':           /* Redraw screen */
  409:                   case CTRL('L'):
  410:                         wrefresh(curscr);
  411:                         break;
  412:                   case 'S':           /* Save game */
  413:                         On_exit = FALSE;
  414:                         save();
  415:                         break;
  416:                   case 'E':           /* Extrapolate */
  417: #ifdef EXTRAP
  418:                         if (last_ex)
  419:                                 break;
  420:                         Finished = TRUE;
  421:                         if (Window != W_FULL)
  422:                                 newscore();
  423:                         prscore(FALSE);
  424:                         wrefresh(Score);
  425:                         last_ex = TRUE;
  426:                         Finished = FALSE;
  427: #else
  428:                         error("%c: command not implemented", c);
  429: #endif
  430:                         break;
  431:                   case '\r':          /* Ignore RETURNs and   */
  432:                   case '\n':          /* Line Feeds           */
  433:                   case ' ':           /* Spaces                */
  434:                   case '\0':          /* and nulls            */
  435:                         break;
  436: #ifdef DEBUG
  437:                   case 'Z':           /* Debug code */
  438:                         if (!Debug && outf == NULL) {
  439:                                 char        buf[MAXPATHLEN];
  440:                                 char        *sp;
  441: 
  442:                                 prompt(FILEPROMPT);
  443:                                 leaveok(Board, FALSE);
  444:                                 refresh();
  445: over:
  446:                                 sp = buf;
  447:                                 while ((*sp = readch()) != '\n') {
  448:                                         if (*sp == killchar())
  449:                                                 goto over;
  450:                                         else if (*sp == erasechar()) {
  451:                                                 if (--sp < buf)
  452:                                                         sp = buf;
  453:                                                 else {
  454:                                                         addch('\b');
  455:                                                         if (*sp < ' ')
  456:                                                             addch('\b');
  457:                                                         clrtoeol();
  458:                                                 }
  459:                                         }
  460:                                         else
  461:                                                 addstr(unctrl(*sp++));
  462:                                         refresh();
  463:                                 }
  464:                                 *sp = '\0';
  465:                                 leaveok(Board, TRUE);
  466:                                 if ((outf = fopen(buf, "w")) == NULL)
  467:                                         warn("%s", buf);
  468:                                 setbuf(outf, (char *)NULL);
  469:                         }
  470:                         Debug = !Debug;
  471:                         break;
  472: #endif
  473:                   default:
  474:                         error("unknown command: %s", unctrl(c));
  475:                         break;
  476:                 }
  477:         }
  478: ret:
  479:         leaveok(Board, TRUE);
  480: }
  481: 
  482: /*
  483:  * return whether or not the player has picked
  484:  */
  485: int
  486: haspicked(pp)
  487:         const PLAY     *pp;
  488: {
  489:         int    card;
  490: 
  491:         if (Topcard <= Deck)
  492:                 return TRUE;
  493:         switch (pp->hand[Card_no]) {
  494:           case C_GAS_SAFE:     case C_SPARE_SAFE:
  495:           case C_DRIVE_SAFE:   case C_RIGHT_WAY:
  496:                 card = 1;
  497:                 break;
  498:           default:
  499:                 card = 0;
  500:                 break;
  501:         }
  502:         return (pp->hand[card] != C_INIT);
  503: }
  504: 
  505: void
  506: account(card)
  507:         CARD   card; 
  508: {
  509:         CARD   oppos;
  510: 
  511:         if (card == C_INIT)
  512:                 return;
  513:         ++Numseen[card];
  514:         if (Play == COMP)
  515:                 switch (card) {
  516:                   case C_GAS_SAFE:
  517:                   case C_SPARE_SAFE:
  518:                   case C_DRIVE_SAFE:
  519:                         oppos = opposite(card);
  520:                         Numgos += Numcards[oppos] - Numseen[oppos];
  521:                         break;
  522:                   case C_CRASH:
  523:                   case C_FLAT:
  524:                   case C_EMPTY:
  525:                   case C_STOP:
  526:                         Numgos++;
  527:                         break;
  528:                 }
  529: }
  530: 
  531: void
  532: prompt(promptno)
  533:         int    promptno;
  534: {
  535:         static const char      *const names[] = {
  536:                                 ">>:Move:",
  537:                                 "Really?",
  538:                                 "Another hand?",
  539:                                 "Another game?",
  540:                                 "Save game?",
  541:                                 "Same file?",
  542:                                 "file:",
  543:                                 "Extension?",
  544:                                 "Overwrite file?",
  545:                         };
  546:         static int     last_prompt = -1;
  547: 
  548:         if (promptno == last_prompt)
  549:                 move(MOVE_Y, MOVE_X + strlen(names[promptno]) + 1);
  550:         else {
  551:                 move(MOVE_Y, MOVE_X);
  552:                 if (promptno == MOVEPROMPT)
  553:                         standout();
  554:                 addstr(names[promptno]);