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

bsd-games/2.17/hunt/hunt/otto.c

    1: /*      $NetBSD: otto.c,v 1.8 2004/11/05 21:30:32 dsl Exp $  */
    2: # ifdef OTTO
    3: /*
    4:  * Copyright (c) 1983-2003, Regents of the University of California.
    5:  * 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 are 
    9:  * met:
   10:  * 
   11:  * + Redistributions of source code must retain the above copyright 
   12:  *   notice, this list of conditions and the following disclaimer.
   13:  * + Redistributions in binary form must reproduce the above copyright 
   14:  *   notice, this list of conditions and the following disclaimer in the 
   15:  *   documentation and/or other materials provided with the distribution.
   16:  * + Neither the name of the University of California, San Francisco nor 
   17:  *   the names of its contributors may be used to endorse or promote 
   18:  *   products derived from this software without specific prior written 
   19:  *   permission.
   20:  * 
   21:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
   22:  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
   23:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
   24:  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
   25:  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
   26:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
   27:  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
   28:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
   29:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
   30:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
   31:  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   32:  */
   33: 
   34: /*
   35:  *      otto - a hunt otto-matic player
   36:  *
   37:  *              This guy is buggy, unfair, stupid, and not extensible.
   38:  *      Future versions of hunt will have a subroutine library for
   39:  *      automatic players to link to.  If you write your own "otto"
   40:  *      please let us know what subroutines you would expect in the
   41:  *      subroutine library.
   42:  *
   43:  *      Id: otto.c,v 1.14 2003/04/16 06:11:54 gregc Exp
   44:  */
   45: 
   46: #include <sys/cdefs.h>
   47: #ifndef lint
   48: __RCSID("$NetBSD: otto.c,v 1.8 2004/11/05 21:30:32 dsl Exp $");
   49: #endif /* not lint */
   50: 
   51: # include       <sys/time.h>
   52: # include       <curses.h>
   53: # include       <ctype.h>
   54: # include       <signal.h>
   55: # include       <stdlib.h>
   56: # include       <unistd.h>
   57: # include       "hunt.h"
   58: 
   59: # undef         WALL
   60: # undef         NORTH
   61: # undef         SOUTH
   62: # undef         WEST
   63: # undef         EAST
   64: # undef         FRONT
   65: # undef         LEFT
   66: # undef         BACK
   67: # undef         RIGHT
   68: 
   69: # ifdef HPUX
   70: # define        random         rand
   71: # endif
   72: 
   73: # ifndef USE_CURSES
   74: extern  char     screen[SCREEN_HEIGHT][SCREEN_WIDTH2];
   75: # define        SCREEN(y, x)   screen[y][x]
   76: # else
   77: # define        SCREEN(y, x)   mvinch(y, x)
   78: # endif
   79: 
   80: # ifndef DEBUG
   81: # define        STATIC         static
   82: # else
   83: # define        STATIC
   84: # endif
   85: 
   86: # define        OPPONENT       "{}i!"
   87: # define        PROPONENT      "^v<>"
   88: # define        WALL           "+\\/#*-|"
   89: # define        PUSHOVER       " bg;*#&"
   90: # define        SHOTS          "$@Oo:"
   91: 
   92: /* number of "directions" */
   93: # define        NUMDIRECTIONS  4
   94: 
   95: /* absolute directions (facings) - counterclockwise */
   96: # define        NORTH          0
   97: # define        WEST           1
   98: # define        SOUTH          2
   99: # define        EAST           3
  100: # define        ALLDIRS                0xf
  101: 
  102: /* relative directions - counterclockwise */
  103: # define        FRONT          0
  104: # define        LEFT           1
  105: # define        BACK           2
  106: # define        RIGHT          3
  107: 
  108: # define        ABSCHARS       "NWSE"
  109: # define        RELCHARS       "FLBR"
  110: # define        DIRKEYS                "khjl"
  111: 
  112: STATIC  char     command[BUFSIZ];
  113: STATIC  int      comlen;
  114: 
  115: # ifdef DEBUG
  116: STATIC FILE     *debug = NULL;
  117: # endif
  118: 
  119: # define        DEADEND                0x1
  120: # define        ON_LEFT                0x2
  121: # define        ON_RIGHT       0x4
  122: # define        ON_SIDE                (ON_LEFT|ON_RIGHT)
  123: # define        BEEN           0x8
  124: # define        BEEN_SAME      0x10
  125: 
  126: struct  item     {
  127:         char   what;
  128:         int    distance;
  129:         int    flags;
  130: };
  131: 
  132: STATIC  struct   item      flbr[NUMDIRECTIONS];
  133: 
  134: # define        fitem  flbr[FRONT]
  135: # define        litem  flbr[LEFT]
  136: # define        bitem  flbr[BACK]
  137: # define        ritem  flbr[RIGHT]
  138: 
  139: STATIC  int              facing;
  140: STATIC  int              row, col;
  141: STATIC  int              num_turns;          /* for wandering */
  142: STATIC  char             been_there[HEIGHT][WIDTH2];
  143: STATIC  struct itimerval pause_time      = { { 0, 0 }, { 0, 55000 }};
  144: 
  145: STATIC  void             attack(int, struct item *);
  146: STATIC  void             duck(int);
  147: STATIC  void             face_and_move_direction(int, int);
  148: STATIC  int              go_for_ammo(char);
  149: STATIC  void             ottolook(int, struct item *);
  150: STATIC  void             look_around(void);
  151: STATIC  SIGNAL_TYPE      nothing(int);
  152: STATIC  int              stop_look(struct item *, char, int, int);
  153: STATIC  void             wander(void);
  154: 
  155: extern  int      Otto_count;
  156: 
  157: STATIC SIGNAL_TYPE
  158: nothing(dummy)
  159:         int dummy __attribute__((__unused__));
  160: {
  161: }
  162: 
  163: void
  164: otto(y, x, face)
  165:         int    y, x;
  166:         char   face;
  167: {
  168:         int            i;
  169:         int            old_mask;
  170: 
  171: # ifdef DEBUG
  172:         if (debug == NULL) {
  173:                 debug = fopen("bug", "w");
  174:                 setbuf(debug, NULL);
  175:         }
  176:         fprintf(debug, "\n%c(%d,%d)", face, y, x);
  177: # endif
  178:         (void) signal(SIGALRM, nothing);
  179:         old_mask = sigblock(sigmask(SIGALRM));
  180:         setitimer(ITIMER_REAL, &pause_time, NULL);
  181:         sigpause(old_mask);
  182:         sigsetmask(old_mask);
  183: 
  184:         /* save away parameters so other functions may use/update info */
  185:         switch (face) {
  186:         case '^':      facing = NORTH; break;
  187:         case '<':      facing = WEST; break;
  188:         case 'v':      facing = SOUTH; break;
  189:         case '>':      facing = EAST; break;
  190:         default:       abort();
  191:         }
  192:         row = y; col = x;
  193:         been_there[row][col] |= 1 << facing;
  194: 
  195:         /* initially no commands to be sent */
  196:         comlen = 0;
  197: 
  198:         /* find something to do */
  199:         look_around();
  200:         for (i = 0; i < NUMDIRECTIONS; i++) {
  201:                 if (strchr(OPPONENT, flbr[i].what) != NULL) {
  202:                         attack(i, &flbr[i]);
  203:                         memset(been_there, 0, sizeof been_there);
  204:                         goto done;
  205:                 }
  206:         }
  207: 
  208:         if (strchr(SHOTS, bitem.what) != NULL && !(bitem.what & ON_SIDE)) {
  209:                 duck(BACK);
  210:                 memset(been_there, 0, sizeof been_there);
  211: # ifdef BOOTS
  212:         } else if (go_for_ammo(BOOT_PAIR)) {
  213:                 memset(been_there, 0, sizeof been_there);
  214:         } else if (go_for_ammo(BOOT)) {
  215:                 memset(been_there, 0, sizeof been_there);
  216: # endif
  217:         } else if (go_for_ammo(GMINE))
  218:                 memset(been_there, 0, sizeof been_there);
  219:         else if (go_for_ammo(MINE))
  220:                 memset(been_there, 0, sizeof been_there);
  221:         else
  222:                 wander();
  223: 
  224: done:
  225:         (void) write(Socket, command, comlen);
  226:         Otto_count += comlen;
  227: # ifdef DEBUG
  228:         (void) fwrite(command, 1, comlen, debug);
  229: # endif
  230: }
  231: 
  232: # define        direction(abs,rel)     (((abs) + (rel)) % NUMDIRECTIONS)
  233: 
  234: STATIC int
  235: stop_look(itemp, c, dist, side)
  236:         struct item    *itemp;
  237:         char   c;
  238:         int    dist;
  239:         int    side;
  240: {
  241:         switch (c) {
  242: 
  243:         case SPACE:
  244:                 if (side)
  245:                         itemp->flags &= ~DEADEND;
  246:                 return 0;
  247: 
  248:         case MINE:
  249:         case GMINE:
  250: # ifdef BOOTS
  251:         case BOOT:
  252:         case BOOT_PAIR:
  253: # endif
  254:                 if (itemp->distance == -1) {
  255:                         itemp->distance = dist;
  256:                         itemp->what = c;
  257:                         if (side < 0)
  258:                                 itemp->flags |= ON_LEFT;
  259:                         else if (side > 0)
  260:                                 itemp->flags |= ON_RIGHT;
  261:                 }
  262:                 return 0;
  263: 
  264:         case SHOT:
  265:         case GRENADE:
  266:         case SATCHEL:
  267:         case BOMB:
  268: # ifdef OOZE
  269:         case SLIME:
  270: # endif
  271:                 if (itemp->distance == -1 || (!side
  272:                     && (itemp->flags & ON_SIDE
  273:                     || itemp->what == GMINE || itemp->what == MINE))) {
  274:                         itemp->distance = dist;
  275:                         itemp->what = c;
  276:                         itemp->flags &= ~ON_SIDE;
  277:                         if (side < 0)
  278:                                 itemp->flags |= ON_LEFT;
  279:                         else if (side > 0)
  280:                                 itemp->flags |= ON_RIGHT;
  281:                 }
  282:                 return 0;
  283: 
  284:         case '{':
  285:         case '}':
  286:         case 'i':
  287:         case '!':
  288:                 itemp->distance = dist;
  289:                 itemp->what = c;
  290:                 itemp->flags &= ~(ON_SIDE|DEADEND);
  291:                 if (side < 0)
  292:                         itemp->flags |= ON_LEFT;
  293:                 else if (side > 0)
  294:                         itemp->flags |= ON_RIGHT;
  295:                 return 1;
  296: 
  297:         default:
  298:                 /* a wall or unknown object */
  299:                 if (side)
  300:                         return 0;
  301:                 if (itemp->distance == -1) {
  302:                         itemp->distance = dist;
  303:                         itemp->what = c;
  304:                 }
  305:                 return 1;
  306:         }
  307: }
  308: 
  309: STATIC void
  310: ottolook(rel_dir, itemp)
  311:         int            rel_dir;
  312:         struct item    *itemp;
  313: {
  314:         int            r, c;
  315:         char           ch;
  316: 
  317:         r = 0;
  318:         itemp->what = 0;
  319:         itemp->distance = -1;
  320:         itemp->flags = DEADEND|BEEN;           /* true until proven false */
  321: 
  322:         switch (direction(facing, rel_dir)) {
  323: 
  324:         case NORTH:
  325:                 if (been_there[row - 1][col] & NORTH)
  326:                         itemp->flags |= BEEN_SAME;
  327:                 for (r = row - 1; r >= 0; r--)
  328:                         for (c = col - 1; c < col + 2; c++) {
  329:                                 ch = SCREEN(r, c);
  330:                                 if (stop_look(itemp, ch, row - r, c - col))
  331:                                         goto cont_north;
  332:                                 if (c == col && !been_there[r][c])
  333:                                         itemp->flags &= ~BEEN;
  334:                         }
  335:         cont_north:
  336:                 if (itemp->flags & DEADEND) {
  337:                         itemp->flags |= BEEN;
  338:                         been_there[r][col] |= NORTH;
  339:                         for (r = row - 1; r > row - itemp->distance; r--)
  340:                                 been_there[r][col] = ALLDIRS;
  341:                 }
  342:                 break;
  343: 
  344:         case SOUTH:
  345:                 if (been_there[row + 1][col] & SOUTH)
  346:                         itemp->flags |= BEEN_SAME;
  347:                 for (r = row + 1; r < HEIGHT; r++)
  348:                         for (c = col - 1; c < col + 2; c++) {
  349:                                 ch = SCREEN(r, c);
  350:                                 if (stop_look(itemp, ch, r - row, col - c))
  351:                                         goto cont_south;
  352:                                 if (c == col && !been_there[r][c])
  353:                                         itemp->flags &= ~BEEN;
  354:                         }
  355:         cont_south:
  356:                 if (itemp->flags & DEADEND) {
  357:                         itemp->flags |= BEEN;
  358:                         been_there[r][col] |= SOUTH;
  359:                         for (r = row + 1; r < row + itemp->distance; r++)
  360:                                 been_there[r][col] = ALLDIRS;
  361:                 }
  362:                 break;
  363: 
  364:         case WEST:
  365:                 if (been_there[row][col - 1] & WEST)
  366:                         itemp->flags |= BEEN_SAME;
  367:                 for (c = col - 1; c >= 0; c--)
  368:                         for (r = row - 1; r < row + 2; r++) {
  369:                                 ch = SCREEN(r, c);
  370:                                 if (stop_look(itemp, ch, col - c, row - r))
  371:                                         goto cont_west;
  372:                                 if (r == row && !been_there[r][c])
  373:                                         itemp->flags &= ~BEEN;
  374:                         }
  375:         cont_west:
  376:                 if (itemp->flags & DEADEND) {
  377:                         itemp->flags |= BEEN;
  378:                         been_there[r][col] |= WEST;
  379:                         for (c = col - 1; c > col - itemp->distance; c--)
  380:                                 been_there[row][c] = ALLDIRS;
  381:                 }
  382:                 break;
  383: 
  384:         case EAST:
  385:                 if (been_there[row][col + 1] & EAST)
  386:                         itemp->flags |= BEEN_SAME;
  387:                 for (c = col + 1; c < WIDTH; c++)
  388:                         for (r = row - 1; r < row + 2; r++) {
  389:                                 ch = SCREEN(r, c);
  390:                                 if (stop_look(itemp, ch, c - col, r - row))
  391:                                         goto cont_east;
  392:                                 if (r == row && !been_there[r][c])
  393:                                         itemp->flags &= ~BEEN;
  394:                         }
  395:         cont_east:
  396:                 if (itemp->flags & DEADEND) {
  397:                         itemp->flags |= BEEN;
  398:                         been_there[r][col] |= EAST;
  399:                         for (c = col + 1; c < col + itemp->distance; c++)
  400:                                 been_there[row][c] = ALLDIRS;
  401:                 }
  402:                 break;
  403: 
  404:         default:
  405:                 abort();
  406:         }
  407: }
  408: 
  409: STATIC void
  410: look_around()
  411: {
  412:         int    i;
  413: 
  414:         for (i = 0; i < NUMDIRECTIONS; i++) {
  415:                 ottolook(i, &flbr[i]);
  416: # ifdef DEBUG
  417:                 fprintf(debug, " ottolook(%c)=%c(%d)(0x%x)",
  418:                         RELCHARS[i], flbr[i].what, flbr[i].distance, flbr[i].flags);
  419: # endif
  420:         }
  421: }
  422: 
  423: /*
  424:  *      as a side effect modifies facing and location (row, col)
  425:  */
  426: 
  427: STATIC void
  428: face_and_move_direction(rel_dir, distance)
  429:         int    rel_dir, distance;
  430: {
  431:         int    old_facing;
  432:         char   cmd;
  433: 
  434:         old_facing = facing;
  435:         cmd = DIRKEYS[facing = direction(facing, rel_dir)];
  436: 
  437:         if (rel_dir != FRONT) {
  438:                 int   i;
  439:                 struct        item   items[NUMDIRECTIONS];
  440: 
  441:                 command[comlen++] = toupper((unsigned char)cmd);
  442:                 if (distance == 0) {
  443:                         /* rotate ottolook's to be in right position */
  444:                         for (i = 0; i < NUMDIRECTIONS; i++)
  445:                                 items[i] =
  446:                                         flbr[(i + old_facing) % NUMDIRECTIONS];
  447:                         memcpy(flbr, items, sizeof flbr);
  448:                 }
  449:         }
  450:         while (distance--) {
  451:                 command[comlen++] = cmd;
  452:                 switch (facing) {
  453: 
  454:                 case NORTH:   row--; break;
  455:                 case WEST:    col--; break;
  456:                 case SOUTH:   row++; break;
  457:                 case EAST:    col++; break;
  458:                 }
  459:                 if (distance == 0)
  460:                         look_around();
  461:         }
  462: }
  463: 
  464: STATIC void
  465: attack(rel_dir, itemp)
  466:         int            rel_dir;
  467:         struct item    *itemp;
  468: {
  469:         if (!(itemp->flags & ON_SIDE)) {
  470:                 face_and_move_direction(rel_dir, 0);
  471:                 command[comlen++] = 'o';
  472:                 command[comlen++] = 'o';
  473:                 duck(FRONT);
  474:                 command[comlen++] = ' ';
  475:         } else if (itemp->distance > 1) {
  476:                 face_and_move_direction(rel_dir, 2);
  477:                 duck(FRONT);
  478:         } else {
  479:                 face_and_move_direction(rel_dir, 1);
  480:                 if (itemp->flags & ON_LEFT)
  481:                         rel_dir = LEFT;
  482:                 else
  483:                         rel_dir = RIGHT;
  484:                 (void) face_and_move_direction(rel_dir, 0);
  485:                 command[comlen++] = 'f';
  486:                 command[comlen++] = 'f';
  487:                 duck(FRONT);
  488:                 command[comlen++] = ' ';
  489:         }
  490: }
  491: 
  492: STATIC void
  493: duck(rel_dir)
  494:         int    rel_dir;
  495: {
  496:         int    dir;
  497: 
  498:         switch (dir = direction(facing, rel_dir)) {
  499: 
  500:         case NORTH:
  501:         case SOUTH:
  502:                 if (strchr(PUSHOVER, SCREEN(row, col - 1)) != NULL)
  503:                         command[comlen++] = 'h';
  504:                 else if (strchr(PUSHOVER, SCREEN(row, col + 1)) != NULL)
  505:                         command[comlen++] = 'l';
  506:                 else if (dir == NORTH
  507:                         && strchr(PUSHOVER, SCREEN(row + 1, col)) != NULL)
  508:                                 command[comlen++] = 'j';
  509:                 else if (dir == SOUTH
  510:                         && strchr(PUSHOVER, SCREEN(row - 1, col)) != NULL)
  511:                                 command[comlen++] = 'k';
  512:                 else if (dir == NORTH)
  513:                         command[comlen++] = 'k';
  514:                 else
  515:                         command[comlen++] = 'j';
  516:                 break;
  517: 
  518:         case WEST:
  519:         case EAST:
  520:                 if (strchr(PUSHOVER, SCREEN(row -