home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / games / volume15 / robothnt / part01 < prev    next >
Encoding:
Internet Message Format  |  1993-01-26  |  54.2 KB

  1. Path: uunet!news.tek.com!master!saab!billr
  2. From: billr@saab.CNA.TEK.COM (Bill Randle)
  3. Newsgroups: comp.sources.games
  4. Subject: v15i032:  robot_hunt - original hunt with a robot, Part01/04
  5. Message-ID: <4188@master.CNA.TEK.COM>
  6. Date: 14 Jan 93 03:13:13 GMT
  7. Sender: news@master.CNA.TEK.COM
  8. Lines: 2113
  9. Approved: billr@saab.CNA.TEK.COM
  10. Xref: uunet comp.sources.games:1531
  11.  
  12. Submitted-by: whatis@ucsd.edu (Steve Boswell)
  13. Posting-number: Volume 15, Issue 32
  14. Archive-name: robot_hunt/Part01
  15. Environment: Curses, Sockets
  16.  
  17. [This was previously posted in alt.sources. It is being posted here so that
  18. it may enjoy a permanent, archived home.  -br]
  19.  
  20. [[From the author:
  21. I've been sitting on this source code for too long.  This is the
  22. original version of hunt, with a hunt robot.  It uses a breadth-first
  23. search to discover the best action it can do at every step.
  24.  
  25. I hesitated to release it because it still had a few peculiarities, but
  26. they're minor, and besides, the robot is already a skilled opponent.
  27.  
  28. I'll release better versions of it at irregular intervals.
  29.  
  30. Enjoy!  (His name is Minotaur, by the way. :-)
  31.  
  32. Comments, questions, and large sums of money can be sent to:
  33.  
  34. Steve Boswell
  35. whatis@ucsd.edu
  36. whatis@gnu.ai.mit.edu
  37. ]]
  38.  
  39. #! /bin/sh
  40. # This is a shell archive.  Remove anything before this line, then unpack
  41. # it by saving it into a file and typing "sh file".  To overwrite existing
  42. # files, type "sh file -c".  You can also feed this as standard input via
  43. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  44. # will see the following message at the end:
  45. #        "End of archive 1 (of 4)."
  46. # Contents:  README MANIFEST expl.c player.h robot.c
  47. # Wrapped by billr@saab on Wed Jan 13 19:04:32 1993
  48. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  49. if test -f 'README' -a "${1}" != "-c" ; then 
  50.   echo shar: Will not clobber existing file \"'README'\"
  51. else
  52. echo shar: Extracting \"'README'\" \(859 characters\)
  53. sed "s/^X//" >'README' <<'END_OF_FILE'
  54. XIf you have an old tcp/ip you might have to turn off the BROADCAST
  55. Xoption; see the Makefile.
  56. X
  57. XHunt is not officially supported by anyone anywhere; however, bug
  58. Xreports will be read and bug fixes/enhancements may be sent out at
  59. Xirregular intervals. Enjoy.
  60. X
  61. X    ucbvax!ucsfcgl!conrad
  62. X    ucsfcgl!conrad@berkeley.edu
  63. X
  64. X---------------------------------------------------------------------
  65. X
  66. XNew addition as of 29-Nov-92:
  67. X
  68. XThere is now a hunt robot.  It mostly works, but sometimes it gets into
  69. Xsteady states & so forth.  A couple of bugs involving differences 
  70. Xbetween BSD 4.2 and 4.3 (mostly with sockets getting reused after
  71. Xthey've closed) have been fixed.  See the man page for more details.
  72. X
  73. XI will sort of support the hunt robot, in that if you find a bug in
  74. Xit, I'll incorporate the fix into the next release.
  75. X
  76. XSteve Boswell
  77. Xwhatis@ucsd.edu
  78. Xwhatis@gnu.ai.mit.edu
  79. END_OF_FILE
  80. if test 859 -ne `wc -c <'README'`; then
  81.     echo shar: \"'README'\" unpacked with wrong size!
  82. fi
  83. # end of 'README'
  84. fi
  85. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  86.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  87. else
  88. echo shar: Extracting \"'MANIFEST'\" \(734 characters\)
  89. sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  90. X   File Name        Archive #    Description
  91. X-----------------------------------------------------------
  92. X MANIFEST                   1    This shipping list
  93. X Makefile                   4    
  94. X README                     1    
  95. X answer.c                   3    
  96. X connect.c                  4    
  97. X draw.c                     3    
  98. X driver.c                   2    
  99. X execute.c                  3    
  100. X expl.c                     1    
  101. X extern.c                   2    
  102. X hunt.6                     3    
  103. X hunt.c                     2    
  104. X hunt.h                     3    
  105. X makemaze.c                 4    
  106. X pathname.c                 4    
  107. X player.h                   1    
  108. X playit.c                   3    
  109. X robot.c                    1    
  110. X shots.c                    2    
  111. X terminal.c                 4    
  112. END_OF_FILE
  113. if test 734 -ne `wc -c <'MANIFEST'`; then
  114.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  115. fi
  116. # end of 'MANIFEST'
  117. fi
  118. if test -f 'expl.c' -a "${1}" != "-c" ; then 
  119.   echo shar: Will not clobber existing file \"'expl.c'\"
  120. else
  121. echo shar: Extracting \"'expl.c'\" \(4898 characters\)
  122. sed "s/^X//" >'expl.c' <<'END_OF_FILE'
  123. X/*
  124. X * Copyright (c) 1985 Regents of the University of California.
  125. X * All rights reserved.
  126. X *
  127. X * Redistribution and use in source and binary forms are permitted
  128. X * provided that the above copyright notice and this paragraph are
  129. X * duplicated in all such forms and that any documentation,
  130. X * advertising materials, and other materials related to such
  131. X * distribution and use acknowledge that the software was developed
  132. X * by the University of California, Berkeley.  The name of the
  133. X * University may not be used to endorse or promote products derived
  134. X * from this software without specific prior written permission.
  135. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  136. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  137. X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  138. X */
  139. X
  140. X#ifndef lint
  141. Xstatic char sccsid[] = "@(#)expl.c    5.2 (Berkeley) 6/27/88";
  142. X#endif /* not lint */
  143. X
  144. X/*
  145. X *  Hunt
  146. X *  Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
  147. X *  San Francisco, California
  148. X */
  149. X
  150. X# include    "hunt.h"
  151. X
  152. X/*
  153. X * showexpl:
  154. X *    Show the explosions as they currently are
  155. X */
  156. Xshowexpl(y, x, type)
  157. Xregister int    y, x;
  158. Xchar        type;
  159. X{
  160. X    register PLAYER    *pp;
  161. X    register EXPL    *ep;
  162. X
  163. X    if (y < 0 || y >= HEIGHT)
  164. X        return;
  165. X    if (x < 0 || x >= WIDTH)
  166. X        return;
  167. X    ep = (EXPL *) malloc(sizeof (EXPL));    /* NOSTRICT */
  168. X    ep->e_y = y;
  169. X    ep->e_x = x;
  170. X    ep->e_char = type;
  171. X    ep->e_next = Expl[0];
  172. X    Expl[0] = ep;
  173. X    for (pp = Player; pp < End_player; pp++) {
  174. X        if (pp->p_maze[y][x] == type)
  175. X            continue;
  176. X        pp->p_maze[y][x] = type;
  177. X        cgoto(pp, y, x);
  178. X        outch(pp, type);
  179. X    }
  180. X# ifdef MONITOR
  181. X    for (pp = Monitor; pp < End_monitor; pp++) {
  182. X        if (pp->p_maze[y][x] == type)
  183. X            continue;
  184. X        pp->p_maze[y][x] = type;
  185. X        cgoto(pp, y, x);
  186. X        outch(pp, type);
  187. X    }
  188. X# endif MONITOR
  189. X    switch (Maze[y][x]) {
  190. X      case WALL1:
  191. X      case WALL2:
  192. X      case WALL3:
  193. X# ifdef RANDOM
  194. X      case DOOR:
  195. X# endif RANDOM
  196. X# ifdef REFLECT
  197. X      case WALL4:
  198. X      case WALL5:
  199. X# endif REFLECT
  200. X        if (y >= UBOUND && y < DBOUND && x >= LBOUND && x < RBOUND)
  201. X            remove_wall(y, x);
  202. X        break;
  203. X    }
  204. X}
  205. X
  206. X/*
  207. X * rollexpl:
  208. X *    Roll the explosions over, so the next one in the list is at the
  209. X *    top
  210. X */
  211. Xrollexpl()
  212. X{
  213. X    register EXPL    *ep;
  214. X    register PLAYER    *pp;
  215. X    register int    y, x;
  216. X    register char    c;
  217. X    register EXPL    *nextep;
  218. X
  219. X    for (ep = Expl[EXPLEN - 1]; ep != NULL; ep = nextep) {
  220. X        nextep = ep->e_next;
  221. X        y = ep->e_y;
  222. X        x = ep->e_x;
  223. X        if (y < UBOUND || y >= DBOUND || x < LBOUND || x >= RBOUND)
  224. X            c = Maze[y][x];
  225. X        else
  226. X            c = SPACE;
  227. X        for (pp = Player; pp < End_player; pp++)
  228. X            if (pp->p_maze[y][x] == ep->e_char) {
  229. X                pp->p_maze[y][x] = c;
  230. X                cgoto(pp, y, x);
  231. X                outch(pp, c);
  232. X            }
  233. X# ifdef MONITOR
  234. X        for (pp = Monitor; pp < End_monitor; pp++)
  235. X            check(pp, y, x);
  236. X# endif MONITOR
  237. X        free((char *) ep);
  238. X    }
  239. X    for (x = EXPLEN - 1; x > 0; x--)
  240. X        Expl[x] = Expl[x - 1];
  241. X    Expl[0] = NULL;
  242. X}
  243. X
  244. X/* There's about 700 walls in the initial maze.  So we pick a number
  245. X * that keeps the maze relatively full. */
  246. X# define MAXREMOVE    40
  247. X
  248. Xstatic    REGEN    removed[MAXREMOVE];
  249. Xstatic    REGEN    *rem_index = removed;
  250. X
  251. X/*
  252. X * remove_wall - add a location where the wall was blown away.
  253. X *         if there is no space left over, put the a wall at
  254. X *         the location currently pointed at.
  255. X */
  256. Xremove_wall(y, x)
  257. Xint    y, x;
  258. X{
  259. X    register REGEN    *r;
  260. X# if defined(MONITOR) || defined(FLY)
  261. X    register PLAYER    *pp;
  262. X# endif MONITOR || FLY
  263. X# ifdef    FLY
  264. X    register char    save_char;
  265. X# endif    FLY
  266. X
  267. X    r = rem_index;
  268. X    while (r->r_y != 0) {
  269. X# ifdef FLY
  270. X        switch (Maze[r->r_y][r->r_x]) {
  271. X          case SPACE:
  272. X          case LEFTS:
  273. X          case RIGHT:
  274. X          case ABOVE:
  275. X          case BELOW:
  276. X          case FLYER:
  277. X            save_char = Maze[r->r_y][r->r_x];
  278. X            goto found;
  279. X        }
  280. X# else FLY
  281. X        if (Maze[r->r_y][r->r_x] == SPACE)
  282. X            break;
  283. X# endif FLY
  284. X        if (++r >= &removed[MAXREMOVE])
  285. X            r = removed;
  286. X    }
  287. X
  288. Xfound:
  289. X    if (r->r_y != 0) {
  290. X        /* Slot being used, put back this wall */
  291. X# ifdef FLY
  292. X        if (save_char == SPACE)
  293. X            Maze[r->r_y][r->r_x] = Orig_maze[r->r_y][r->r_x];
  294. X        else {
  295. X            pp = play_at(r->r_y, r->r_x);
  296. X            if (pp->p_flying >= 0)
  297. X                pp->p_flying += rand_num(10);
  298. X            else {
  299. X                pp->p_flying = rand_num(20);
  300. X                pp->p_flyx = 2 * rand_num(6) - 5;
  301. X                pp->p_flyy = 2 * rand_num(6) - 5;
  302. X            }
  303. X            pp->p_over = Orig_maze[r->r_y][r->r_x];
  304. X            pp->p_face = FLYER;
  305. X            Maze[r->r_y][r->r_x] = FLYER;
  306. X            showexpl(r->r_y, r->r_x, FLYER);
  307. X        }
  308. X# else FLY
  309. X        Maze[r->r_y][r->r_x] = Orig_maze[r->r_y][r->r_x];
  310. X# endif FLY
  311. X# ifdef RANDOM
  312. X        if (rand_num(100) == 0)
  313. X            Maze[r->r_y][r->r_x] = DOOR;
  314. X# endif RANDOM
  315. X# ifdef REFLECT
  316. X        if (rand_num(100) == 0)        /* one percent of the time */
  317. X            Maze[r->r_y][r->r_x] = WALL4;
  318. X# endif REFLECT
  319. X# ifdef MONITOR
  320. X        for (pp = Monitor; pp < End_monitor; pp++)
  321. X            check(pp, r->r_y, r->r_x);
  322. X# endif MONITOR
  323. X    }
  324. X
  325. X    r->r_y = y;
  326. X    r->r_x = x;
  327. X    if (++r >= &removed[MAXREMOVE])
  328. X        rem_index = removed;
  329. X    else
  330. X        rem_index = r;
  331. X
  332. X    Maze[y][x] = SPACE;
  333. X# ifdef MONITOR
  334. X    for (pp = Monitor; pp < End_monitor; pp++)
  335. X        check(pp, y, x);
  336. X# endif MONITOR
  337. X}
  338. END_OF_FILE
  339. if test 4898 -ne `wc -c <'expl.c'`; then
  340.     echo shar: \"'expl.c'\" unpacked with wrong size!
  341. fi
  342. # end of 'expl.c'
  343. fi
  344. if test -f 'player.h' -a "${1}" != "-c" ; then 
  345.   echo shar: Will not clobber existing file \"'player.h'\"
  346. else
  347. echo shar: Extracting \"'player.h'\" \(284 characters\)
  348. sed "s/^X//" >'player.h' <<'END_OF_FILE'
  349. X/* Stuff needed by both playit.c and robot.c */
  350. X
  351. Xextern char screen[24][80], blanks[80];
  352. Xextern int cur_row, cur_col;
  353. X
  354. X# undef  CTRL
  355. X# define CTRL(x)    ('x' & 037)
  356. X
  357. X#define    GETCHR(fd)    (--(fd)->_cnt >= 0 ? *(fd)->_ptr++&0377 : getchr(fd))
  358. X
  359. Xextern void setup_to_play();
  360. Xextern FILE *inf;
  361. END_OF_FILE
  362. if test 284 -ne `wc -c <'player.h'`; then
  363.     echo shar: \"'player.h'\" unpacked with wrong size!
  364. fi
  365. # end of 'player.h'
  366. fi
  367. if test -f 'robot.c' -a "${1}" != "-c" ; then 
  368.   echo shar: Will not clobber existing file \"'robot.c'\"
  369. else
  370. echo shar: Extracting \"'robot.c'\" \(42868 characters\)
  371. sed "s/^X//" >'robot.c' <<'END_OF_FILE'
  372. X# ifdef ROBOT
  373. X
  374. X#include "hunt.h"
  375. X#include "player.h"
  376. X#include <sys/time.h>
  377. X#include <errno.h>
  378. X#include <setjmp.h>
  379. X
  380. X/* Used for debugging. */
  381. X#define debug(str) { long _l; leave (-1, str); _l = *(long *)(-1); }
  382. X/* #define debug(str) */
  383. X
  384. X#ifdef DEBUG_FILE
  385. Xstatic FILE *debugFile;
  386. X#endif DEBUG_FILE
  387. X
  388. X/* How long we wait for volcano information to decay. */
  389. X#define VOLCANO_DECAY 5
  390. X
  391. X/* How far away from volcanos we should stay. */
  392. X#define VOLCANO_DISTANCE 5
  393. X
  394. X/* How long we wait for in-range information to decay. */
  395. X#define IN_RANGE_DECAY 1
  396. X
  397. X/* How far in front of an enemy is considered "in range". */
  398. X#define IN_RANGE_DISTANCE BULSPD * 2
  399. X
  400. X/* How long we wait for ammo information to decay. */
  401. X#define AMMO_DECAY 3
  402. X
  403. X/* How long we wait for 'enemy suspected' info to decay. */
  404. X#define ENEMY_DECAY 25
  405. X
  406. X/* The maximum number of walls we'll shoot through to get to
  407. X   an enemy. */
  408. X#define MAX_THRU_WALLS 4
  409. X
  410. X/* Directions. */
  411. X#define north 0
  412. X#define east 1
  413. X#define south 2
  414. X#define west 3
  415. X
  416. X/* Maps DirectionType to turning command character. */
  417. Xchar turn[4] = { 'K', 'L', 'J', 'H' };
  418. X
  419. X/* Maps DirectionType to moving command character. */
  420. Xchar move[4] = { 'k', 'l', 'j', 'h' };
  421. X
  422. X/* Maps DirectionType to x-move and y-move. */
  423. Xint dir_to_xm[4] = { 0, 1, 0, -1 };
  424. Xint dir_to_ym[4] = { -1, 0, 1, 0 };
  425. X#define turn_around(d) \
  426. X    ((d + 2) % 4)
  427. X
  428. X/* Neighbor information for BFS nodes. */
  429. X#define BFS_WALL 0
  430. X#define BFS_PRED 1
  431. X#define BFS_SUCC 2
  432. X
  433. X/* Holds information about each location in the maze.  This info
  434. X   is generated by a breadth-first search. */
  435. Xtypedef struct bfs_node bfs_node, *bfs_node_ptr;
  436. Xstruct bfs_node
  437. X{
  438. X    /* Fields specifying how desirable this path is. */
  439. X
  440. X    char enemies_seen;
  441. X        /* Enemies actually seen along this path. */
  442. X    char enemies_suspected;
  443. X        /* Enemies suspected to be along this path. */
  444. X    short mines_seen;
  445. X        /* The amount of ammo we gain along this path. */
  446. X    long lowest_time_last_seen;
  447. X        /* The time we saw the area we haven't seen in the longest
  448. X           time along this path. */
  449. X    short distance_to_target;
  450. X        /* How far we are from the path's best target. */
  451. X
  452. X    /* Fields specifying what we saw at this exact location. */
  453. X
  454. X    long time_last_seen;
  455. X        /* The turn # that this node was seen last. */
  456. X    short enemy_seen_decay;
  457. X        /* If an enemy is suspected to be here, this number is
  458. X           greater than zero, and is decremented every turn.
  459. X           If this number is zero, no enemy is suspected here. */
  460. X    short danger_seen_decay;
  461. X        /* If this area is deemed dangerous (e.g. flying ammo, lava)
  462. X           then this number is greater than zero, and is decremented
  463. X           every turn.  If this is zero, this area is not dangerous. */
  464. X
  465. X    /* Fields specifying our position in the BFS paths. */
  466. X
  467. X    char successors;
  468. X        /* The number of successors we have to wait to be done
  469. X           before we can get done. */
  470. X    char neighbors[4];
  471. X        /* Indexed by direction.  0 == Wall, 1 == Predecessor,
  472. X           2 == Successor. */
  473. X
  474. X    /* Fields specifying our bookkeeping info. */
  475. X
  476. X    char visited;
  477. X        /* Nonzero if this location has been visited. */
  478. X    char in_to_do_queue;
  479. X        /* Nonzero if this location is in the "to do" queue. */
  480. X    short next_x, next_y;
  481. X        /* The next node in the "to do" or "path end" queue. */
  482. X};
  483. X
  484. X/* Holds info about our enemies. */
  485. Xtypedef struct
  486. X{
  487. X    char name[NAMELEN];
  488. X        /* Our enemy's name. */
  489. X    int vis_state;
  490. X        /* 0 == none, 1 == scanning, 2 == cloaking, -1 == must be read
  491. X           from the screen. */
  492. X    float score;
  493. X        /* Their score. */
  494. X} enemy, *enemy_ptr;
  495. X
  496. X/* Holds info about the robot's statistics, as displayed on the
  497. X   right side of the screen. */
  498. Xtypedef struct
  499. X{
  500. X    char name[NAMELEN];
  501. X        /* Our name.  If name[0] == '\0', re-read it from the screen. */
  502. X    int ammo;
  503. X        /* Ammo left.  If -1, re-read it from the screen. */
  504. X    int scan;
  505. X        /* -1 == re-read it from the screen, 0 == not scanning,
  506. X           1 == scanning. */
  507. X    int cloak;
  508. X        /* -1 == re-read it from the screen, 0 == not cloaking,
  509. X           1 == cloaking. */
  510. X    int gun;
  511. X        /* -1 == re-read it from the screen, 0 == not OK,
  512. X           1 == OK. */
  513. X    int curr_damage;
  514. X        /* Current hit points.  If -1, re-read it from the screen. */
  515. X    int tot_damage;
  516. X        /* Total hit points possible.  If -1, re-read it from the
  517. X           screen. */
  518. X    int kills;
  519. X        /* Number of kills we have.  If -1, re-read it from the
  520. X           screen. */
  521. X    enemy enemies[MAXPL - 1];
  522. X        /* Our enemies. */
  523. X} screen_stats, *screen_stats_ptr;
  524. X
  525. X/* Robot data.  (In most cases, a value of -1 means "unknown".) */
  526. X
  527. Xint robot_player;            /* Nonzero if this client is a robot */
  528. Xint daemon_player;            /* Nonzero if this client is a daemon too */
  529. Xint robot_x;                /* Horizontal position of robot */
  530. Xint robot_y;                /* Vertical position of robot */
  531. Xint robot_face;                /* Which way the robot is facing */
  532. Xunsigned long robot_time=1;    /* Robot's internal clock */
  533. Xscreen_stats robot_stats;    /* Our statistics. */
  534. X
  535. X/* Tracks playing-field changes that affect the robot's behavior. */
  536. Xstatic bfs_node maze[HEIGHT + 1][WIDTH + 1];
  537. X
  538. X/* Keeps track of an enemy within killing distance, in
  539. X  each direction. */
  540. Xtypedef struct
  541. X{
  542. X    int distance;
  543. X        /* How far away he is.  0 == no enemy this way. */
  544. X    int walls;
  545. X        /* How many shootable walls are between us. */
  546. X} active_enemy, active_enemy_ptr;
  547. X
  548. X/* Our active enemies, one for each direction. */
  549. Xstatic active_enemy active_enemies[4];
  550. X
  551. X/* Needed for the breadth-first search. */
  552. X
  553. Xstatic int to_do_head_x = -1, to_do_head_y, to_do_tail_x,
  554. X        to_do_tail_y;
  555. X    /* The "to do" queue. */
  556. Xstatic int path_end_head_x = -1, path_end_head_y, path_end_tail_x,
  557. X        path_end_tail_y;
  558. X    /* The "path end" queue. */
  559. X
  560. Xjmp_buf robot_jbuf;        /* Used to (q)uit instantly */
  561. X
  562. X/* Returns -1 if the number is negative, 1 if the number is
  563. X   positive, and 0 if it is 0. */
  564. Xstatic int
  565. Xsgn (number)
  566. Xint number;
  567. X{
  568. X    if (number > 0)
  569. X        return 1;
  570. X    else if (number < 0)
  571. X        return -1;
  572. X    else return 0;
  573. X}
  574. X
  575. X/* Print a message in the status line (bottom of the screen.) */
  576. Xstatic void
  577. Xmessage (msg)
  578. Xchar *msg;
  579. X{
  580. X    if (!daemon_player)
  581. X    {
  582. X        int old_cur_row, old_cur_col;
  583. X
  584. X        old_cur_row = cur_row;
  585. X        old_cur_col = cur_col;
  586. X            mvcur (cur_row, cur_col, 23, 0);
  587. X        cur_row = 23;
  588. X        cur_col = 0;
  589. X        put_str (msg);
  590. X        clear_eol();
  591. X        fflush (stdout);
  592. X        mvcur (cur_row, cur_col, old_cur_row, old_cur_col);
  593. X        cur_row = old_cur_row;
  594. X        cur_col = old_cur_col;
  595. X    }
  596. X}
  597. X
  598. X/* Returns nonzero if the given char is a wall. */
  599. Xstatic int
  600. Xis_a_wall (ch)
  601. Xchar ch;
  602. X{
  603. X    return
  604. X    (
  605. X        ch == WALL1
  606. X     || ch == WALL2
  607. X     || ch == WALL3
  608. X# ifdef REFLECT
  609. X     || ch == WALL4
  610. X     || ch == WALL5
  611. X# endif REFLECT
  612. X    );
  613. X}
  614. X
  615. X/* Map a player direction character to a direction. */
  616. Xstatic int
  617. Xplayer_char_to_direction (ch)
  618. Xunsigned char ch;
  619. X{
  620. X    switch (ch)
  621. X    {
  622. X        case ABOVE:
  623. X        case PLAYER_ABOVE:
  624. X            return north;
  625. X
  626. X        case BELOW:
  627. X        case PLAYER_BELOW:
  628. X            return south;
  629. X
  630. X        case LEFTS:
  631. X        case PLAYER_LEFT:
  632. X            return west;
  633. X
  634. X        case RIGHT:
  635. X        case PLAYER_RIGHT:
  636. X            return east;
  637. X
  638. X        default:
  639. X            debug ("player_char_to_direction failed");
  640. X    }
  641. X}
  642. X
  643. X/* Mark a straight hallway as dangerous. */
  644. Xvoid
  645. Xdangerous_hall (danger_y, danger_x, danger_face, how_far, how_bad)
  646. Xint danger_y, danger_x, danger_face, how_far, how_bad;
  647. X{
  648. X    int xm = dir_to_xm[danger_face];
  649. X    int ym = dir_to_ym[danger_face];
  650. X
  651. X    /* Mark everything in the hall dangerous, up to the first wall or
  652. X       terra incognita. */
  653. X    do
  654. X    {
  655. X        /* Mark here dangerous. */
  656. X        if (maze[danger_y][danger_x].danger_seen_decay < how_bad)
  657. X            maze[danger_y][danger_x].danger_seen_decay = how_bad;
  658. X
  659. X        /* Move down the hall. */
  660. X        danger_x += xm;
  661. X        danger_y += ym;
  662. X
  663. X        /* Remember how far we've gone. */
  664. X        how_far--;
  665. X
  666. X        /* Stop at the first wall or terra
  667. X           incognita. */
  668. X    } while (how_far > 0 &&
  669. X    maze[danger_y][danger_x].time_last_seen != 0
  670. X    && !is_a_wall (screen[danger_y][danger_x]));
  671. X}
  672. X
  673. X/* Gather information. */
  674. Xstatic void
  675. Xrobot_see (ch)
  676. Xunsigned char ch;
  677. X{
  678. X    /* Very retentive debugging checks. */
  679. X    if (path_end_head_x != -1)
  680. X        debug ("path end queue has members before robot_see");
  681. X    if (to_do_head_x != -1)
  682. X        debug ("to do queue has members before robot_see");
  683. X
  684. X    /* Distinguish between changes in the arena & status area. */
  685. X    if (cur_row <= HEIGHT - 1)
  686. X    {
  687. X        if (cur_col <= WIDTH)
  688. X        {
  689. X            /* Handle changes in the arena. */
  690. X
  691. X            /* If we've never seen this area before, we have now. */
  692. X            if (!is_a_wall (screen[cur_row][cur_col]))
  693. X                maze[cur_row][cur_col].time_last_seen = robot_time;
  694. X
  695. X            /* Keep track of what's disappearing. */
  696. X            switch (screen[cur_row][cur_col])
  697. X            {
  698. X                case DOOR:
  699. X                case WALL1:
  700. X                case WALL2:
  701. X                case WALL3:
  702. X                case WALL4:
  703. X                case WALL5:
  704. X                    /* A wall disappeared.  */
  705. X                    break;
  706. X
  707. X                case KNIFE:
  708. X                case SHOT:
  709. X                case GRENADE:
  710. X                case SATCHEL:
  711. X                case BOMB:
  712. X                case SLIME:
  713. X# ifdef VOLCANO
  714. X                case LAVA:
  715. X# endif VOLCANO
  716. X                    /* Something deadly disappeared.  We'll let the
  717. X                       decay counter tell us when it's really gone. */
  718. X                    break;
  719. X
  720. X                case MINE:
  721. X                case GMINE:
  722. X                    /* A mine disappeared.  We'll notice this during
  723. X                       the BFS. */
  724. X                    break;
  725. X
  726. X                case PLAYER_ABOVE:
  727. X                case PLAYER_BELOW:
  728. X                case PLAYER_RIGHT:
  729. X                case PLAYER_LEFT:
  730. X                    /* We were just undrawn.  Now we don't know what
  731. X                       way we're facing. */
  732. X                    robot_face = -1;
  733. X                    break;
  734. X
  735. X                case ABOVE:
  736. X                case BELOW:
  737. X                case RIGHT:
  738. X                case LEFTS:
  739. X                    /* An enemy disappeared.  Remember that we saw
  740. X                       him here. */
  741. X                    maze[cur_row][cur_col].enemy_seen_decay
  742. X                        = ENEMY_DECAY;
  743. X                    break;
  744. X
  745. X                case SPACE:
  746. X                    /* Something has moved into a space.  We don't
  747. X                       do anything about this here. */
  748. X                    break;
  749. X
  750. X                default:
  751. X                    /* Unrecognized character.  Ignore it. */
  752. X                    break;
  753. X            }
  754. X
  755. X            /* Keep track of what's appearing. */
  756. X            switch (ch)
  757. X            {
  758. X                case DOOR:
  759. X                case WALL1:
  760. X                case WALL2:
  761. X                case WALL3:
  762. X# ifdef REFLECT
  763. X                case WALL4:
  764. X                case WALL5:
  765. X# endif REFLECT
  766. X                    /* A wall just appeared.  Mark the area underneath
  767. X                       it as terra incognita. */
  768. X                    maze[cur_row][cur_col].time_last_seen = 0;
  769. X                    break;
  770. X
  771. X                case KNIFE:
  772. X                case SHOT:
  773. X                case GRENADE:
  774. X                case SATCHEL:
  775. X                case BOMB:
  776. X                case SLIME:
  777. X# ifdef VOLCANO
  778. X                case LAVA:
  779. X# endif VOLCANO
  780. X                    /* Either someone just fired or a weapon finished
  781. X                       its current move.  Mark the entire effective
  782. X                       hallway as dangerous. */
  783. X                    {
  784. X                        int i;        /* A direction to be marked. */
  785. X
  786. X                        /* Mark all directions dangerous. */
  787. X                        for (i = north; i <= west; i++)
  788. X                            dangerous_hall (cur_row, cur_col, i,
  789. X                            WIDTH / BULSPD, AMMO_DECAY);
  790. X                    }
  791. X                    break;
  792. X
  793. X                case MINE:
  794. X                case GMINE:
  795. X                    /* A new mine.  Make a list of mines in the BFS. */
  796. X                    break;
  797. X
  798. X                case PLAYER_ABOVE:
  799. X                case PLAYER_BELOW:
  800. X                case PLAYER_RIGHT:
  801. X                case PLAYER_LEFT:
  802. X                    /* It's ourselves.  Now we know where we are. */
  803. X                    robot_x = cur_col;
  804. X                    robot_y = cur_row;
  805. X                    robot_face = player_char_to_direction (ch);
  806. X                    break;
  807. X
  808. X                case ABOVE:
  809. X                case BELOW:
  810. X                case RIGHT:
  811. X                case LEFTS:
  812. X                    /* A player has been spotted. */
  813. X
  814. X                    /* Remember where he was. */
  815. X                    maze[cur_row][cur_col].enemy_seen_decay
  816. X                        = ENEMY_DECAY;
  817. X
  818. X                    /* Consider everything in front of him as
  819. X                       being dangerous. */
  820. X                    dangerous_hall (cur_row, cur_col,
  821. X                        player_char_to_direction (ch),
  822. X                        IN_RANGE_DISTANCE, IN_RANGE_DECAY);
  823. X                    break;
  824. X
  825. X                case SPACE:
  826. X                    /* Something just disappeared. */
  827. X                    break;
  828. X
  829. X                default:
  830. X                    /* Unrecognized character.  Probably someone
  831. X                       flying. */
  832. X                    break;
  833. X            }
  834. X        }
  835. X        else
  836. X        {
  837. X            /* Handle changes in the status area.  For each stat
  838. X               line where a change occurs, mark that stat as needing
  839. X               to be re-read. */
  840. X            switch (cur_row)
  841. X            {
  842. X                case STAT_NAME_ROW:
  843. X                    /* Our name has changed.  Re-read it. */
  844. X                    robot_stats.name[0] = '\0';
  845. X                    break;
  846. X
  847. X                case STAT_AMMO_ROW:
  848. X                    /* Our ammo count has changed.  Re-read it. */
  849. X                    robot_stats.ammo = -1;
  850. X                    break;
  851. X
  852. X                case STAT_SCAN_ROW:
  853. X                    /* Our scanning status has changed.  Re-read it. */
  854. X                    robot_stats.scan = -1;
  855. X                    break;
  856. X
  857. X                case STAT_CLOAK_ROW:
  858. X                    /* Our cloaking status has changed.  Re-read it. */
  859. X                    robot_stats.cloak = -1;
  860. X                    break;
  861. X
  862. X                case STAT_GUN_ROW:
  863. X                    /* Our gun's condition has changed.  Re-read it. */
  864. X                    robot_stats.gun = -1;
  865. X                    break;
  866. X
  867. X                case STAT_DAM_ROW:
  868. X                    /* Our damage status has changed.  Re-read it. */
  869. X                    robot_stats.curr_damage = robot_stats.tot_damage
  870. X                        = -1;
  871. X                    break;
  872. X
  873. X                case STAT_KILL_ROW:
  874. X                    /* Our number of kills has changed.  Re-read it. */
  875. X                    robot_stats.kills = -1;
  876. X                    break;
  877. X
  878. X                default:
  879. X                    /* See if the change was within the enemy list. */
  880. X                    if (cur_row >= STAT_PLAY_ROW + 1 && cur_row
  881. X                    < STAT_PLAY_ROW + MAXPL)
  882. X                    {
  883. X                        /* It was.  Mark that enemy as needing to
  884. X                           be re-read from the screen. */
  885. X                        robot_stats.enemies[cur_row -
  886. X                            (STAT_PLAY_ROW + 1)].vis_state = -1;
  887. X                    }
  888. X
  889. X                    /* Otherwise, ignore the change.  It's probably
  890. X                       a monitor change (which we don't track.) */
  891. X                    break;
  892. X            }
  893. X        }
  894. X    }
  895. X
  896. X    /* Print the new character to the screen. */
  897. X    put_ch (ch);
  898. X}
  899. X
  900. X/* Given a direction to look in, mark everything in that direction as
  901. X   having been seen now. */
  902. Xstatic void
  903. Xlook_down_hall (xm, ym)
  904. Xint xm,ym;
  905. X{
  906. X    int x,y;        /* Where we're looking */
  907. X    char ch;        /* What we found */
  908. X
  909. X    /* Start where we are. */
  910. X    x = robot_x;
  911. X    y = robot_y;
  912. X    ch = 0;
  913. X
  914. X    while (1)
  915. X    {
  916. X        /* Move down the hallway, time-stamp everything.  If we
  917. X           thought any enemies were here, we know for sure now. */
  918. X        maze[y][x].time_last_seen = robot_time;
  919. X        x += xm;
  920. X        y += ym;
  921. X
  922. X        /* If this was a door, stop.  Thus we see the door. */
  923. X        if (ch == DOOR)
  924. X            break;
  925. X
  926. X        /* If we're at the end of the hall, or if we find a door,
  927. X           stop. */
  928. X        ch = screen[y][x];
  929. X        if (is_a_wall (ch))
  930. X            break;
  931. X    }
  932. X}
  933. X
  934. X/* For the breadth-first search done in update_info().  Puts a
  935. X   location onto the "to do" queue. */
  936. Xstatic void
  937. Xdo_node (y, x, pred_dir)
  938. Xint x, y, pred_dir;
  939. X{
  940. X    bfs_node_ptr current;
  941. X    int i;
  942. X
  943. X    /* Find the current node. */
  944. X    current = &(maze[y][x]);
  945. X
  946. X    /* Set up the current node. */
  947. X    current->next_x = current->next_y = -1;
  948. X    current->in_to_do_queue = 1;
  949. X    for (i = north; i <= west; i++)
  950. X        current->neighbors[i] = ((i == pred_dir) ? BFS_PRED : BFS_WALL);
  951. X
  952. X    /* If the queue is empty, this is easy. */
  953. X    if (to_do_head_x == -1)
  954. X    {
  955. X        /* Start the queue. */
  956. X        to_do_head_x = to_do_tail_x = x;
  957. X        to_do_head_y = to_do_tail_y = y;
  958. X    }
  959. X    else
  960. X    {
  961. X        /* Put this at the end of the queue. */
  962. X        maze[to_do_tail_y][to_do_tail_x].next_x = x;
  963. X        maze[to_do_tail_y][to_do_tail_x].next_y = y;
  964. X        to_do_tail_x = x;
  965. X        to_do_tail_y = y;
  966. X    }
  967. X}
  968. X
  969. X/* For the breadth-first search done in update_info().  Puts a
  970. X   location onto the "path end" queue. */
  971. Xstatic void
  972. Xpath_end_node (current_y, current_x)
  973. Xint current_y, current_x;
  974. X{
  975. X    bfs_node_ptr current;
  976. X    int i;
  977. X
  978. X    /* Set up the current node. */
  979. X    current = &(maze[current_y][current_x]);
  980. X    current->next_x = current->next_y = -1;
  981. X    for (i = north; i <= west; i++)
  982. X        if (current->neighbors[i] == BFS_SUCC)
  983. X            current->neighbors[i] = BFS_WALL;
  984. X    current->successors = 0;
  985. X
  986. X    /* If the queue is empty, this is easy. */
  987. X    if (path_end_head_x == -1)
  988. X    {
  989. X        /* Start the queue. */
  990. X        path_end_head_x = path_end_tail_x = current_x;
  991. X        path_end_head_y = path_end_tail_y = current_y;
  992. X    }
  993. X    else
  994. X    {
  995. X        /* Put this at the end of the queue. */
  996. X        maze[path_end_tail_y][path_end_tail_x].next_x = current_x;
  997. X        maze[path_end_tail_y][path_end_tail_x].next_y = current_y;
  998. X        path_end_tail_x = current_x;
  999. X        path_end_tail_y = current_y;
  1000. X    }
  1001. X}
  1002. X
  1003. X/* Compare two nodes' optimality. */
  1004. Xstatic int
  1005. Xnode_compare (left, right)
  1006. Xbfs_node_ptr left, right;
  1007. X{
  1008. X    /* Compare by danger. */
  1009. X    if (left->danger_seen_decay < right->danger_seen_decay)
  1010. X        return -1;
  1011. X    else if (left->danger_seen_decay > right->danger_seen_decay)
  1012. X        return 1;
  1013. X
  1014. X    /* Compare by enemies actually seen. */
  1015. X    if (left->enemies_seen > right->enemies_seen)
  1016. X        return -1;
  1017. X    else if (left->enemies_seen < right->enemies_seen)
  1018. X        return 1;
  1019. X
  1020. X    /* Compare by enemies suspected. */
  1021. X    if (left->enemies_suspected > right->enemies_suspected)
  1022. X        return -1;
  1023. X    else if (left->enemies_suspected < right->enemies_suspected)
  1024. X        return 1;
  1025. X
  1026. X    /* Compare by ammunition available. */
  1027. X    if (left->mines_seen > right->mines_seen)
  1028. X        return -1;
  1029. X    else if (left->mines_seen < right->mines_seen)
  1030. X        return 1;
  1031. X
  1032. X    /* If we've seen anything (i.e. at least one of the stats
  1033. X       above is not zero) then these nodes are equal.  Otherwise,
  1034. X       the robot gets into steady states. */
  1035. X    if (left->enemies_seen != 0
  1036. X    || right->enemies_seen != 0
  1037. X    || left->enemies_suspected != 0
  1038. X    || right->enemies_suspected != 0
  1039. X    || left->mines_seen != 0
  1040. X    || right->mines_seen != 0)
  1041. X        return 0;
  1042. X
  1043. X    /* Compare by most aged area. */
  1044. X    if (left->lowest_time_last_seen < right->lowest_time_last_seen)
  1045. X        return -1;
  1046. X    else if (left->lowest_time_last_seen > right->lowest_time_last_seen)
  1047. X        return 1;
  1048. X
  1049. X    /* Compare by distance from the robot. */
  1050. X    if (left->distance_to_target < right->distance_to_target)
  1051. X        return -1;
  1052. X    else if (left->distance_to_target > right->distance_to_target)
  1053. X        return 1;
  1054. X
  1055. X    /* The two nodes are equal. */
  1056. X    return 0;
  1057. X}
  1058. X
  1059. X/* Count the # of walls between ourself and the target, put the result
  1060. X   in "walls", put the distance to the target in "distance", and put
  1061. X   the direction the target is in in "dir".  Return 0 if everything
  1062. X   looks fine, return 1 if there are unshootable walls between us and
  1063. X   the target, and return 2 if we & the target are not lined up. */
  1064. Xstatic int
  1065. Xwalls_between (y, x, walls, distance, dir)
  1066. Xint y, x, *walls, *distance, *dir;
  1067. X{
  1068. X    int xm, ym;        /* The direction the target is from us */
  1069. X    int status;        /* What we're finding */
  1070. X
  1071. X    /* Set up to look. */
  1072. X    *distance = 0;
  1073. X    *walls = 0;
  1074. X    status = 0;
  1075. X    xm = sgn (robot_x - x);
  1076. X    ym = sgn (robot_y - y);
  1077. X
  1078. X    /* If we're not directly aligned, return 2 now. */
  1079. X    if (xm != 0 && ym != 0)
  1080. X        return 2;
  1081. X
  1082. X    /* Look at the entire path from here to there, count the
  1083. X       number of walls. */
  1084. X    while (x != robot_x || y != robot_y)
  1085. X    {
  1086. X        /* If this is a wall, record it. */
  1087. X        switch (screen[y][x])
  1088. X        {
  1089. X            case WALL1:
  1090. X            case WALL2:
  1091. X            case WALL3:
  1092. X                /* This is a wall we can shoot through. */
  1093. X                (*walls)++;
  1094. X                break;
  1095. X
  1096. X            case DOOR:
  1097. X#ifdef REFLECT
  1098. X            case WALL4:
  1099. X            case WALL5:
  1100. X#endif REFLECT
  1101. X                /* This is a wall we can't shoot through. */
  1102. X                (*walls)++;
  1103. X                status = 1;
  1104. X                break;
  1105. X
  1106. X            default:
  1107. X                /* We don't record anything else. */
  1108. X                break;
  1109. X        }
  1110. X
  1111. X        /* Move along. */
  1112. X        x += xm;
  1113. X        y += ym;
  1114. X        (*distance)++;
  1115. X    }
  1116. X
  1117. X    /* If there are too many walls, forget it. */
  1118. X    if ((*walls) > MAX_THRU_WALLS)
  1119. X        return 1;
  1120. X
  1121. X    /* Save what direction the target is in. */
  1122. X    if (xm == 0 && ym == -1)
  1123. X        *dir = south;
  1124. X    else if (xm == 1 && ym == 0)
  1125. X        *dir = west;
  1126. X    else if (xm == 0 && ym == 1)
  1127. X        *dir = north;
  1128. X    else if (xm == -1 && ym == 0)
  1129. X        *dir = east;
  1130. X    else
  1131. X        debug ("Funky xm/ym");
  1132. X
  1133. X    return status;
  1134. X}
  1135. X
  1136. X/* Update our information about the playing field. */
  1137. Xstatic void
  1138. Xupdate_info()
  1139. X{
  1140. X    unsigned char ch;
  1141. X    int x,y;
  1142. X
  1143. X    /* Keep getting info from the driver until there isn't any.
  1144. X       Also make sure that we've reappeared.  (We could be flying,
  1145. X       and there's no point in continuing until we know where we
  1146. X       are.) */
  1147. X    do
  1148. X    {
  1149. X        ch = GETCHR (inf);
  1150. X
  1151. X        switch (ch & 0377)
  1152. X        {
  1153. X          case MOVE:
  1154. X            y = GETCHR(inf);
  1155. X            x = GETCHR(inf);
  1156. X            if (!daemon_player)
  1157. X            {
  1158. X                mvcur(cur_row, cur_col, y, x);
  1159. X            }
  1160. X            cur_row = y;
  1161. X            cur_col = x;
  1162. X            break;
  1163. X          case ADDCH:
  1164. X            ch = GETCHR(inf);
  1165. X            robot_see(ch);
  1166. X            break;
  1167. X          case CLRTOEOL:
  1168. X            clear_eol();
  1169. X            break;
  1170. X          case CLEAR:
  1171. X            clear_screen();
  1172. X            break;
  1173. X          case REFRESH:
  1174. X            fflush(stdout);
  1175. X            break;
  1176. X          case REDRAW:
  1177. X            redraw_screen();
  1178. X            fflush(stdout);
  1179. X            break;
  1180. X          case ENDWIN:
  1181. X            if ((ch = GETCHR(inf)) == LAST_PLAYER)
  1182. X                Last_player = TRUE;
  1183. X            ch = EOF;
  1184. X            /* Fall through */
  1185. X
  1186. X          case EOF:
  1187. X            fflush(stdout);
  1188. X            (void) fclose (inf);
  1189. X            longjmp (robot_jbuf, 1);
  1190. X            /* NOTREACHED */
  1191. X
  1192. X          case BELL:
  1193. X            if (!daemon_player)
  1194. X            {
  1195. X                putchar(CTRL(G));
  1196. X            }
  1197. X            break;
  1198. X          case READY:
  1199. X            (void) fflush(stdout);
  1200. X            (void) GETCHR (inf);
  1201. X            break;
  1202. X          default:
  1203. X            robot_see(ch);
  1204. X            break;
  1205. X        }
  1206. X    } while (ch != READY || robot_face == -1);
  1207. X
  1208. X    /* Make sure all our statistics from the right side of the screen
  1209. X       are up to date. */
  1210. X
  1211. X    /* Check our name. */
  1212. X    if (robot_stats.name[0] == '\0')
  1213. X        sscanf (&(screen[STAT_NAME_ROW][STAT_LABEL_COL]), "%-13.13s",
  1214. X            robot_stats.name);
  1215. X
  1216. X    /* Check our ammo. */
  1217. X    if (robot_stats.ammo == -1)
  1218. X        sscanf (&(screen[STAT_AMMO_ROW][STAT_VALUE_COL]), "%3d",
  1219. X            &(robot_stats.ammo));
  1220. X
  1221. X    /* Check our scanning status.  (It's faster to just update it
  1222. X       than check it first.) */
  1223. X    robot_stats.scan = (screen[STAT_SCAN_ROW][STAT_VALUE_COL + 1]
  1224. X        == 'o') ? 1 : 0;
  1225. X
  1226. X    /* Check our cloaking status.  (It's faster to just update it
  1227. X       than check it first.) */
  1228. X    robot_stats.cloak = (screen[STAT_CLOAK_ROW][STAT_VALUE_COL + 1]
  1229. X        == 'o') ? 1 : 0;
  1230. X
  1231. X    /* Check our gun's status.  (It's faster to just update it
  1232. X       than check it first.) */
  1233. X    robot_stats.gun = (screen[STAT_GUN_ROW][STAT_VALUE_COL + 1]
  1234. X        == 'o') ? 1 : 0;
  1235. X
  1236. X    /* Check our current/total hit points. */
  1237. X    if (robot_stats.curr_damage == -1 || robot_stats.tot_damage == -1)
  1238. X        sscanf (&(screen[STAT_DAM_ROW][STAT_VALUE_COL]), "%2d/%2d",
  1239. X            &(robot_stats.curr_damage), &(robot_stats.tot_damage));
  1240. X
  1241. X    /* Check our kill count. */
  1242. X    if (robot_stats.kills == -1)
  1243. X        sscanf (&(screen[STAT_KILL_ROW][STAT_VALUE_COL]), "%3d",
  1244. X            &(robot_stats.kills));
  1245. X
  1246. X    /* Check each of our enemies. */
  1247. X#ifdef CHECK_ENEMIES
  1248. X    {
  1249. X        int i;
  1250. X
  1251. X        for (i = 0; i < MAXPL; i++)
  1252. X        {
  1253. X            char new_vis;        /* Enemy's new visibility state. */
  1254. X
  1255. X            /* Check that enemy. */
  1256. X            if (robot_stats.enemies[i].vis_state == -1)
  1257. X            {
  1258. X                if (screen[STAT_PLAY_ROW + 1 + i][STAT_NAME_COL] != ' ')
  1259. X                {
  1260. X                    /* Update that enemy. */
  1261. X                    sscanf (&(screen[STAT_PLAY_ROW + 1 + i]
  1262. X                        [STAT_NAME_COL]), "%5.2f%c%-10.10s",
  1263. X                        &(robot_stats.enemies[i].score),
  1264. X                        &new_vis,
  1265. X                        robot_stats.enemies[i].name);
  1266. X                    switch (new_vis)
  1267. X                    {
  1268. X                        case '+':
  1269. X                            robot_stats.enemies[i].vis_state = 1;
  1270. X                            break;
  1271. X                        case '*':
  1272. X                            robot_stats.enemies[i].vis_state = 2;
  1273. X                            break;
  1274. X                        case ' ':
  1275. X                            robot_stats.enemies[i].vis_state = 0;
  1276. X                            break;
  1277. X                        default:
  1278. X                            debug ("Illegal enemy vis_state");
  1279. X                    }
  1280. X                }
  1281. X                else
  1282. X                {
  1283. X                    /* There's no enemy here any more. */
  1284. X                    robot_stats.enemies[i].name[0] = '\0';
  1285. X                }
  1286. X            }
  1287. X        }
  1288. X    }
  1289. X#endif CHECK_ENEMIES
  1290. X
  1291. X    /* Advance one time unit. */
  1292. X    robot_time++;
  1293. X
  1294. X#ifdef DEBUG_FILE
  1295. X    {
  1296. X        char msg[60];
  1297. X
  1298. X        fprintf (debugFile, "Turn #%ld\n-----------\n", robot_time);
  1299. X        fflush (debugFile);
  1300. X        sprintf (msg, "%ld", robot_time);
  1301. X        message (msg);
  1302. X        fflush (stdout);
  1303. X    }
  1304. X#endif DEBUG_FILE
  1305. X
  1306. X    /* Look around us, update our knowledge of the area. */
  1307. X
  1308. X    /* Look up, if we can. */
  1309. X    if (robot_face != south)
  1310. X        look_down_hall (0, -1);
  1311. X
  1312. X    /* Look down, if we can. */
  1313. X    if (robot_face != north)
  1314. X        look_down_hall (0, 1);
  1315. X
  1316. X    /* Look right, if we can. */
  1317. X    if (robot_face != west)
  1318. X        look_down_hall (1, 0);
  1319. X
  1320. X    /* Look left, if we can. */
  1321. X    if (robot_face != east)
  1322. X        look_down_hall (-1, 0);
  1323. X
  1324. X    /* Before we do a breadth-first search, we must make sure
  1325. X       that the maze structure is correct. */
  1326. X    for (y = 0; y <= HEIGHT; y++)
  1327. X    {
  1328. X        for (x = 0; x <= WIDTH; x++)
  1329. X        {
  1330. X            bfs_node_ptr current;
  1331. X
  1332. X            /* Check each node's correctness. */
  1333. X            current = &(maze[y][x]);
  1334. X
  1335. X            if (current->visited != 0)
  1336. X                debug ("visited true before BFS");
  1337. X            if (current->in_to_do_queue != 0)
  1338. X                debug ("in_to_do_queue true before BFS");
  1339. X            if (current->successors != 0)
  1340. X                debug ("successors != 0 before BFS");
  1341. X        }
  1342. X    }
  1343. X
  1344. X    /* Do a breadth-first search through the maze, find the best
  1345. X       action to do. */
  1346. X    if (to_do_head_x != -1)
  1347. X        debug ("to_do list isn't empty");
  1348. X    if (path_end_head_x != -1)
  1349. X        debug ("path_end list isn't empty");
  1350. X
  1351. X    /* Start the "to do" queue with the robot's location.
  1352. X       (There is no predecessor where the robot is.) */
  1353. X    do_node (robot_y, robot_x, north);
  1354. X    maze[robot_y][robot_x].neighbors[north] = BFS_WALL;
  1355. X#ifdef DEBUG_FILE
  1356. X    fprintf (debugFile, "Robot at (%d, %d)\n", robot_x, robot_y);
  1357. X    fflush (debugFile);
  1358. X#endif DEBUG_FILE
  1359. X
  1360. X    /* Look ahead, find everything on the way. */
  1361. X    while (to_do_head_x != -1)
  1362. X    {
  1363. X        bfs_node_ptr current;
  1364. X        int current_x, current_y;
  1365. X        int i;
  1366. X
  1367. X        /* Pull a node off the "to do" list. */
  1368. X        current_x = to_do_head_x;
  1369. X        current_y = to_do_head_y;
  1370. X        to_do_head_x = maze[current_y][current_x].next_x;
  1371. X        to_do_head_y = maze[current_y][current_x].next_y;
  1372. X        current = &(maze[current_y][current_x]);
  1373. X        current->next_x = current->next_y = -1;
  1374. X        current->in_to_do_queue = 0;
  1375. X
  1376. X#ifdef DEBUG_FILE
  1377. X        fprintf (debugFile, "Visited (%d,%d)\n", current_x, current_y);
  1378. X        fflush (debugFile);
  1379. X#endif DEBUG_FILE
  1380. X
  1381. X        /* Make sure it hasn't been visited yet. */
  1382. X        if (current->visited == 1)
  1383. X            debug ("visit out of order");
  1384. X        current->visited = 1;
  1385. X
  1386. X        /* Reset this node. */
  1387. X        current->enemies_seen = 0;
  1388. X        current->enemies_suspected = 0;
  1389. X        current->mines_seen = 0;
  1390. X        current->lowest_time_last_seen = robot_time + 1;
  1391. X
  1392. X        /* If we've never seen this area, end the path here. */
  1393. X        if (current->time_last_seen == 0)
  1394. X        {
  1395. X            path_end_node (current_y, current_x);
  1396. X#ifdef DEBUG_FILE
  1397. X            fprintf (debugFile,
  1398. X                "Path ended at (%d,%d) -- terra incognita\n",
  1399. X                current_x, current_y);
  1400. X            fflush (debugFile);
  1401. X#endif DEBUG_FILE
  1402. X            goto toDoLoopEnd;
  1403. X        }
  1404. X
  1405. X        /* Handle anything we can find in this pass. */
  1406. X        switch (screen[current_y][current_x])
  1407. X        {
  1408. X# ifdef VOLCANO
  1409. X            case LAVA:
  1410. X                /* Volcano!  Run back VOLCANO_DISTANCE steps and
  1411. X                   set the danger to VOLCANO_DECAY. */
  1412. X                {
  1413. X                    int how_far = VOLCANO_DISTANCE;
  1414. X                    int danger_x, danger_y;
  1415. X                    bfs_node_ptr danger_node;
  1416. X
  1417. X                    /* Start where the lava is, run backwards. */
  1418. X                    danger_x = current_x;
  1419. X                    danger_y = current_y;
  1420. X                    while (--how_far >= 0)
  1421. X                    {
  1422. X                        int i;        /* Used to find predecessor. */
  1423. X
  1424. X                        /* If we meet up with the robot, stop .*/
  1425. X                        if (danger_x == robot_x && danger_y == robot_y)
  1426. X                            break;
  1427. X
  1428. X                        /* Find the node. */
  1429. X                        danger_node = &(maze[danger_y][danger_x]);
  1430. X
  1431. X                        /* Mark this area as dangerous. */
  1432. X                        if (danger_node->danger_seen_decay
  1433. X                        < VOLCANO_DECAY)
  1434. X                            danger_node->danger_seen_decay
  1435. X                                = VOLCANO_DECAY;
  1436. X
  1437. X                        /* Find the predecessor. */
  1438. X                        for (i = north; i <= west; i++)
  1439. X                            if (danger_node->neighbors[i] == BFS_PRED)
  1440. X                                break;
  1441. X                        if (i > west)
  1442. X                            break;
  1443. X
  1444. X                        /* Move there. */
  1445. X                        danger_x += dir_to_xm[i];
  1446. X                        danger_y += dir_to_ym[i];
  1447. X                    }
  1448. X                }
  1449. X
  1450. X                /* Don't go any further. */
  1451. X                path_end_node (current_y, current_x);
  1452. X#ifdef DEBUG_FILE
  1453. X                fprintf (debugFile,
  1454. X                    "Path ended at (%d,%d) -- lava\n",
  1455. X                    current_x, current_y);
  1456. X                fflush (debugFile);
  1457. X#endif DEBUG_FILE
  1458. X                goto toDoLoopEnd;
  1459. X# endif VOLCANO
  1460. X
  1461. X            default:
  1462. X                break;
  1463. X        }
  1464. X
  1465. X        /* Take all successors that aren't the predecessor and
  1466. X           remember to do them. */
  1467. X        for (i = north; i <= west; i++)
  1468. X        {
  1469. X            int new_x, new_y;
  1470. X            bfs_node_ptr successor;
  1471. X
  1472. X            /* If this direction is the predecessor, don't look. */
  1473. X            if (current->neighbors[i] == BFS_PRED)
  1474. X                continue;
  1475. X
  1476. X            /* Move into places we haven't been. */
  1477. X            new_x = current_x + dir_to_xm[i];
  1478. X            new_y = current_y + dir_to_ym[i];
  1479. X            successor = &(maze[new_y][new_x]);
  1480. X
  1481. X            /* If we've moved into somewhere that's already been
  1482. X               visited, then we end the path here. */
  1483. X            if (successor->visited != 1
  1484. X            && successor->in_to_do_queue != 1
  1485. X            && !is_a_wall (screen[new_y][new_x]))
  1486. X                current->neighbors[i] = BFS_SUCC;
  1487. X            else current->neighbors[i] = BFS_WALL;
  1488. X        }
  1489. X
  1490. X        /* Now that we know where our successors are, remember to
  1491. X           do them. */
  1492. X        for (i = north; i <= west; i++)
  1493. X        {
  1494. X            if (current->neighbors[i] == BFS_SUCC)
  1495. X            {
  1496. X                (current->successors)++;
  1497. X                do_node (current_y + dir_to_ym[i],
  1498. X                    current_x + dir_to_xm[i], turn_around(i));
  1499. X            }
  1500. X        }
  1501. X
  1502. X        /* If we didn't have any successors, end the path here. */
  1503. X        if (current->successors == 0)
  1504. X        {
  1505. X            path_end_node (current_y, current_x);
  1506. X#ifdef DEBUG_FILE
  1507. X            fprintf (debugFile,
  1508. X                "Path ended at (%d,%d) -- dead end\n",
  1509. X                current_x, current_y);
  1510. X            fflush (debugFile);
  1511. X#endif DEBUG_FILE
  1512. X        }
  1513. X
  1514. XtoDoLoopEnd:;
  1515. X    }
  1516. X
  1517. X    /* Reset the "active enemy" list. */
  1518. X    {
  1519. X        int i;
  1520. X
  1521. X        for (i = north; i <= west; i++)
  1522. X            active_enemies[i].distance = 0;
  1523. X    }
  1524. X
  1525. X    /* Now process each path back to the robot, generate total
  1526. X       statistics. */
  1527. X    while (path_end_head_x != -1)
  1528. X    {
  1529. X        bfs_node_ptr current;
  1530. X        int current_x, current_y;
  1531. X
  1532. X        /* Pull a node off the "path end" list. */
  1533. X        current_x = path_end_head_x;
  1534. X        current_y = path_end_head_y;
  1535. X        path_end_head_x = maze[current_y][current_x].next_x;
  1536. X        path_end_head_y = maze[current_y][current_x].next_y;
  1537. X        current = &(maze[current_y][current_x]);
  1538. X        current->next_x = current->next_y = -1;
  1539. X
  1540. X        /* Run back along this path until we find more successors
  1541. X           than ourselves. */
  1542. X        while (1)
  1543. X        {
  1544. X            int predecessor;
  1545. X            int i;
  1546. X            int a_stat_dominated = 0;
  1547. X                /* Nonzero as soon as any stat has been dominated. */
  1548. X
  1549. X            /* If this is the robot's node, skip it. */
  1550. X            if (current_x == robot_x && current_y == robot_y)
  1551. X                break;
  1552. X
  1553. X            /* Un-mark the 'visited' flag on the way back. */
  1554. X            current = &(maze[current_y][current_x]);
  1555. X#ifdef DEBUG_FILE
  1556. X            fprintf (debugFile, "Unvisited (%d,%d), time=%ld\n",
  1557. X                current_x, current_y, current->time_last_seen);
  1558. X            fflush (debugFile);
  1559. X#endif DEBUG_FILE
  1560. X            if (current->visited == 0)
  1561. X                debug ("un-visit out of order");
  1562. X            current->visited = 0;
  1563. X
  1564. X            /* Set up to be compared to successors. */
  1565. X            current->distance_to_target = 0;
  1566. X
  1567. X            /* Figure in the statistics of our best successor. */
  1568. X            for (i = north; i <= west; i++)
  1569. X            {
  1570. X                int successor_x, successor_y;
  1571. X                bfs_node_ptr successor;
  1572. X                int dominated = 0;
  1573. X                    /* Nonzero if one of the stats has already
  1574. X                       dominated.  We use this to set the distance. */
  1575. X
  1576. X                /* Find our predecessor, while we're at it. */
  1577. X                if (current->neighbors[i] == BFS_PRED)
  1578. X                    predecessor = i;
  1579. X
  1580. X                /* Find the current successor. */
  1581. X                if (current->neighbors[i] != BFS_SUCC)
  1582. X                    continue;
  1583. X                successor_x = current_x + dir_to_xm[i];
  1584. X                successor_y = current_y + dir_to_ym[i];
  1585. X                successor = &(maze[successor_y][successor_x]);
  1586. X
  1587. X                /* Remember the most dominant of each stat. */
  1588. X                if (current->enemies_seen < successor->enemies_seen)
  1589. X                {
  1590. X                    /* The successor's stat was better: remember it. */
  1591. X                    current->enemies_seen = successor->enemies_seen;
  1592. X
  1593. X                    /* If we're the first stat to dominate, then
  1594. X                       remember that successor's distance from the
  1595. X                       robot.  This way we find the first good thing
  1596. X                       in our path, and don't ignore the less good
  1597. X                       ones for the more desirable ones. */
  1598. X                    if (a_stat_dominated == 0)
  1599. X                    {
  1600. X                        a_stat_dominated = 1;
  1601. X                        dominated = 1;
  1602. X                        current->distance_to_target
  1603. X                            = successor->distance_to_target;
  1604. X                    }
  1605. X                    if (dominated == 0)
  1606. X                    {
  1607. X                        dominated = 1;
  1608. X                        if (current->distance_to_target
  1609. X                        > successor->distance_to_target)
  1610. X                                current->distance_to_target
  1611. X                                = successor->distance_to_target;
  1612. X                    }
  1613. X                }
  1614. X
  1615. X                if (current->enemies_suspected
  1616. X                < successor->enemies_suspected)
  1617. X                {
  1618. X                    current->enemies_suspected
  1619. X                        = successor->enemies_suspected;
  1620. X                    if (a_stat_dominated == 0)
  1621. X                    {
  1622. X                        a_stat_dominated = 1;
  1623. X                        dominated = 1;
  1624. X                        current->distance_to_target
  1625. X                            = successor->distance_to_target;
  1626. X                    }
  1627. X                    if (dominated == 0)
  1628. X                    {
  1629. X                        dominated = 1;
  1630. X                        if (current->distance_to_target
  1631. X                        > successor->distance_to_target)
  1632. X                                current->distance_to_target
  1633. X                                = successor->distance_to_target;
  1634. X                    }
  1635. X                }
  1636. X
  1637. X                if (current->mines_seen < successor->mines_seen)
  1638. X                {
  1639. X                    current->mines_seen = successor->mines_seen;
  1640. X                    if (a_stat_dominated == 0)
  1641. X                    {
  1642. X                        a_stat_dominated = 1;
  1643. X                        dominated = 1;
  1644. X                        current->distance_to_target
  1645. X                            = successor->distance_to_target;
  1646. X                    }
  1647. X                    if (dominated == 0)
  1648. X                    {
  1649. X                        dominated = 1;
  1650. X                        if (current->distance_to_target
  1651. X                        > successor->distance_to_target)
  1652. X                                current->distance_to_target
  1653. X                                = successor->distance_to_target;
  1654. X                    }
  1655. X                }
  1656. X
  1657. X                if (current->lowest_time_last_seen
  1658. X                > successor->lowest_time_last_seen)
  1659. X                {
  1660. X                    current->lowest_time_last_seen
  1661. X                        = successor->lowest_time_last_seen;
  1662. X                    /* This stat does not dominate other
  1663. X                       stats as far as distance goes. */
  1664. X                }
  1665. X            }
  1666. X
  1667. X            /* If no stat dominated, then allow the lowest
  1668. X               time last seen to dominate. */
  1669. X            if (!a_stat_dominated)
  1670. X            {
  1671. X                int i;
  1672. X
  1673. X                /* None of the successor nodes dominated.  Allow
  1674. X                   lowest_time_last_seen to dominate. */
  1675. X                for (i = north; i <= west; i++)
  1676. X                {
  1677. X                    int successor_x, successor_y;
  1678. X                    bfs_node_ptr successor;
  1679. X    
  1680. X                    /* Find the current successor. */
  1681. X                    if (current->neighbors[i] != BFS_SUCC)
  1682. X                        continue;
  1683. X                    successor_x = current_x + dir_to_xm[i];
  1684. X                    successor_y = current_y + dir_to_ym[i];
  1685. X                    successor = &(maze[successor_y][successor_x]);
  1686. X
  1687. X                    if (current->lowest_time_last_seen
  1688. X                    == successor->lowest_time_last_seen)
  1689. X                    {
  1690. X                        current->distance_to_target
  1691. X                            = successor->distance_to_target;
  1692. X                        break;
  1693. X                    }
  1694. X                }
  1695. X            }
  1696. X
  1697. X            /* Add a step. */
  1698. X            (current->distance_to_target)++;
  1699. X
  1700. X            /* Add in its local statistics. */
  1701. X
  1702. X            /* Figure in the last time this area was seen. */
  1703. X            if (current->time_last_seen
  1704. X            < current->lowest_time_last_seen)
  1705. X            {
  1706. X                current->lowest_time_last_seen
  1707. X                    = current->time_last_seen;
  1708. X                current->distance_to_target = 0;
  1709. X            }
  1710. X
  1711. X            /* Figure in enemy's suspected locations. */
  1712. X            if (current->enemy_seen_decay > 0)
  1713. X            {
  1714. X                (current->enemies_suspected)++;
  1715. X                current->distance_to_target = 0;
  1716. X            }
  1717. X
  1718. X            /* Figure in what's on the screen here. */
  1719. X            switch (screen[current_y][current_x])
  1720. X            {
  1721. X                case MINE:
  1722. X                    /* There's a mine here. Count it up. */
  1723. X                    current->mines_seen += BULREQ;
  1724. X                    current->distance_to_target = 0;
  1725. X                    break;
  1726. X
  1727. X                case GMINE:
  1728. X                    /* There's a mine here. Count it up. */
  1729. X                    current->mines_seen += GRENREQ;
  1730. X                    current->distance_to_target = 0;
  1731. X                    break;
  1732. X
  1733. X                case ABOVE:
  1734. X                case BELOW:
  1735. X                case RIGHT:
  1736. X                case LEFTS:
  1737. X                {
  1738. X                    int target_dist;
  1739. X                        /* Distance between us & enemy. */
  1740. X                    int target_walls;
  1741. X                        /* Shootable walls between us & enemy. */
  1742. X                    int target_dir;
  1743. X                        /* Direction enemy is in. */
  1744. X
  1745. X                    /* An enemy is here.  Count it up. */
  1746. X                    (current->enemies_seen)++;
  1747. X                    current->distance_to_target = 0;
  1748. X
  1749. X                    /* If this enemy is within killing distance,
  1750. X                       go for it. */
  1751. X                    if (walls_between (current_y, current_x,
  1752. X                    &target_walls, &target_dist, &target_dir) == 0)
  1753. X                    {
  1754. X                        int best_dist;
  1755. X
  1756. X                        /* If this enemy is the closest to us on
  1757. X                           this side, remember him. */
  1758. X                        best_dist = active_enemies[target_dir].distance;
  1759. X                        if (best_dist == 0 || best_dist > target_dist)
  1760. X                        {
  1761. X                            active_enemies[target_dir].distance
  1762. X                                = target_dist;
  1763. X                            active_enemies[target_dir].walls
  1764. X                                = target_walls;
  1765. X                        }
  1766. X                    }
  1767. X                    break;
  1768. X                }
  1769. X
  1770. X                default:
  1771. X                    break;
  1772. X            }
  1773. X
  1774. X            /* Move to our predecessor.  If it has more successors
  1775. X               than us, get a new path end. */
  1776. XmoveToPred:
  1777. X            current_x += dir_to_xm[predecessor];
  1778. X            current_y += dir_to_ym[predecessor];
  1779. X            (maze[current_y][current_x].successors)--;
  1780. X            if (maze[current_y][current_x].successors != 0)
  1781. X                break;
  1782. X            if (maze[current_y][current_x].next_x != -1)
  1783. X                debug ("mixup in backward path following");
  1784. X        }
  1785. X    }
  1786. X    maze[robot_y][robot_x].visited = 0;        /* The un-base case. */
  1787. X
  1788. X    /* Now we've generated the overall results of moving in each
  1789. X       legal direction.  Decay all our suspicions. */
  1790. X    for (y = 0; y <= HEIGHT; y++)
  1791. X    {
  1792. X        for (x = 0; x <= WIDTH; x++)
  1793. X        {
  1794. X            bfs_node_ptr current = &(maze[y][x]);
  1795. X
  1796. X            /* Decay our suspected enemy locations. */
  1797. X            if (current->enemy_seen_decay != 0)
  1798. X                (current->enemy_seen_decay)--;
  1799. X
  1800. X            /* Decay our suspected danger locations. */
  1801. X            if (current->danger_seen_decay != 0)
  1802. X                (current->danger_seen_decay)--;
  1803. X
  1804. X            /* We don't check terra incognita for debugging. */
  1805. X            if (current->time_last_seen == 0)
  1806. X                continue;
  1807. X
  1808. X            /* While we're at it, make sure that everything
  1809. X               got reset. */
  1810. X            if (current->visited != 0)
  1811. X                debug ("visited true after BFS");
  1812. X            if (current->in_to_do_queue != 0)
  1813. X                debug ("in_to_do_queue true after BFS");
  1814. X            if (current->successors != 0)
  1815. X                debug ("successors != 0 after BFS");
  1816. X        }
  1817. X    }
  1818. X
  1819. X#ifdef DEBUG_FILE
  1820. X    fprintf (debugFile,"\n");
  1821. X    fflush (debugFile);
  1822. X#endif DEBUG_FILE
  1823. X}
  1824. X
  1825. X/* Send a character to the server. */
  1826. Xstatic void
  1827. Xsend_char(ch)
  1828. Xunsigned char ch;
  1829. X{
  1830. X    /* Send the character. */
  1831. X    (void) write (Socket, &ch, 1);
  1832. X}
  1833. X
  1834. X/* Hi, world!  Your ass is grass. */
  1835. Xvoid
  1836. Xdo_robot()
  1837. X{
  1838. X    /* Debugging shit. */
  1839. X#ifdef DEBUG_FILE
  1840. X    debugFile = fopen ("./debug_file","w");
  1841. X#endif DEBUG_FILE
  1842. X
  1843. X    /* Clear the maze out, reset all our private variables. */
  1844. X    /* {
  1845. X        Heh, heh, heh... with this commented out, we remember between
  1846. X        deaths!
  1847. X
  1848. X        int i, j;
  1849. X
  1850. X        robot_time = 1;
  1851. X        for (i = 0; i <= HEIGHT; i++)
  1852. X            for (j = 0; j <= WIDTH; j++)
  1853. X                maze[i][j].time_last_seen = 0;
  1854. X    } */
  1855. X
  1856. X    /* Find our starting location. */
  1857. X    robot_x = robot_y = 0;
  1858. X    robot_face = -1;
  1859. X
  1860. X    /* Go get 'em! */
  1861. X    if (!setjmp (robot_jbuf))
  1862. X    {
  1863. X        /* Keep doing this until we get longjmp'd. */
  1864. X        while (1)
  1865. X        {
  1866. X            int dest_dir = -1;        /* Which way we're going. */
  1867. X            int dest_distance = 0;    /* How far we have to go. */
  1868. X            int i;                    /* A direction we might go. */
  1869. X            int must_escape = 0;    /* Nonzero is we must escape. */
  1870. X            char our_cmd;            /* What we decide to do. */
  1871. X
  1872. X            /* Let the screen update. */
  1873. X            update_info();
  1874. X
  1875. X            /* Wait a bit. */
  1876. X            usleep (150000);
  1877. X
  1878. X            /* We don't suspect enemies where we're standing. */
  1879. X            maze[robot_y][robot_x].enemy_seen_decay = 0;
  1880. X
  1881. X            /* We don't know what to do yet. */
  1882. X            our_cmd = '\0';
  1883. X
  1884. X            /* If there's an enemy within killing distance, go get
  1885. X               him. */
  1886. X            for (i = north; i <= west; i++)
  1887. X            {
  1888. X                int enemy_distance;
  1889. X
  1890. X                /* Find out how far away he is. */
  1891. X                enemy_distance = active_enemies[i].distance;
  1892. X
  1893. X                /* If ever there's an enemy with zero walls
  1894. X                   between us, and his direction is dangerous,
  1895. X                   then we must escape. */
  1896. X                if (active_enemies[i].walls == 0
  1897. X                && maze[robot_y + dir_to_ym[i]][robot_x + dir_to_xm[i]]
  1898. X                .danger_seen_decay != 0)
  1899. X                {
  1900. X                    must_escape = 1;
  1901. X                }
  1902. X
  1903. X                /* Find the closest active enemy. */
  1904. X                if (enemy_distance != 0 && (dest_distance == 0
  1905. X                || enemy_distance < dest_distance))
  1906. X                {
  1907. X                    dest_dir = i;
  1908. X                    dest_distance = enemy_distance;
  1909. X                }
  1910. X            }
  1911. X
  1912. X            /* If we must escape, do so. */
  1913. X            if (must_escape)
  1914. X            {
  1915. X                int i;
  1916. X                    /* A direction we could go. */
  1917. X                int safe_dir;
  1918. X                    /* The direction we're going. */
  1919. X                bfs_node_ptr safe_node;
  1920. X                    /* Why we're going there. */
  1921. X
  1922. X                /* Find a not-dangerous direction to go in. */
  1923. X                safe_dir = -1;
  1924. X                safe_node = NULL;
  1925. X                for (i = north; i <= west; i++)
  1926. X                {
  1927. X                    int look_x, look_y;
  1928. X                    bfs_node_ptr current_look;
  1929. X                        /* Where and why we're looking. */
  1930. X
  1931. X                    /* Look in a direction. */
  1932. X                    look_x = robot_x + dir_to_xm[i];
  1933. X                    look_y = robot_y + dir_to_ym[i];
  1934. X                    current_look = &(maze[look_y][look_x]);
  1935. X
  1936. X                    /* If it's not possible to go there, don't. */
  1937. X                    if (is_a_wall (screen[look_y][look_x])
  1938. X                    || current_look->time_last_seen == 0)
  1939. X                        continue;
  1940. X
  1941. X                    /* If it's not safe to go in that direction,
  1942. X                       don't. */
  1943. X                    if (current_look->danger_seen_decay != 0)
  1944. X                        continue;
  1945. X
  1946. X                    /* It's safe to go that way.  Out of all the
  1947. X                       safe ways, is it the best? */
  1948. X                    if (safe_node == NULL
  1949. X                    || node_compare (safe_node, current_look) == 1)
  1950. X                    {
  1951. X                        safe_dir = i;
  1952. X                        safe_node = current_look;
  1953. X                    }
  1954. X                }
  1955. X
  1956. X                /* If we have a safe direction to go in, move there
  1957. X                   without turning. */
  1958. X                if (safe_dir != -1)
  1959. X                    our_cmd = move[safe_dir];
  1960. X            }
  1961. X
  1962. X            /* If we have an enemy, charge! */
  1963. X            if (our_cmd == '\0' && dest_dir != -1 && !must_escape)
  1964. X            {
  1965. X                /* Kill!  Kill!  Kill! */
  1966. X
  1967. X                /* If we have to turn to face him, do that. */
  1968. X                if (robot_face != dest_dir)
  1969. X                    our_cmd = turn[dest_dir];
  1970. X
  1971. X                /* If our gun can't fire, or if we're right up
  1972. X                   against our active enemy, then move towards
  1973. X                   him. */
  1974. X                else if (robot_stats.gun == 0 || robot_stats.ammo == 0)
  1975. X                    our_cmd = move[dest_dir];
  1976. X
  1977. X                /* If we have lots of ammo, throw bigger stuff. */
  1978. X                else if (robot_stats.ammo > 40
  1979. X                && active_enemies[dest_dir].distance > 5)
  1980. X                    our_cmd = 'F';
  1981. X                else if (robot_stats.ammo > 20
  1982. X                && active_enemies[dest_dir].distance > 3)
  1983. X                    our_cmd = 'g';
  1984. X
  1985. X                /* Fire! */
  1986. X                else
  1987. X                    our_cmd = 'f';
  1988. X            }
  1989. X
  1990. X            /* Examine the results of the BFS, see what the best
  1991. X               way to go is. */
  1992. X            if (our_cmd == '\0')
  1993. X            {
  1994. X                int i;
  1995. X                    /* The direction we're thinking about. */
  1996. X                bfs_node_ptr current_node;
  1997. X                    /* What we're thinking about. */
  1998. X                int best_dir = -1;
  1999. X                    /* The direction we're going. */
  2000. X                bfs_node_ptr best_node = NULL;
  2001. X                    /* The reason we're going there. */
  2002. X
  2003. X                /* Find the best direction. */
  2004. X                for (i = north; i <= west; i++)
  2005. X                {
  2006. X                    int current_x, current_y;
  2007. X
  2008. X                    /* Get info on this direction. */
  2009. X                    current_x = robot_x + dir_to_xm[i];
  2010. X                    current_y = robot_y + dir_to_ym[i];
  2011. X                    current_node = &(maze[current_y][current_x]);
  2012. X
  2013. X                    /* If this is the best so far, remember it. */
  2014. X                    if (!is_a_wall (screen[current_y][current_x])
  2015. X                    && (best_node == NULL
  2016. X                       || node_compare (best_node, current_node) == 1))
  2017. X                    {
  2018. X                        best_node = current_node;
  2019. X                        best_dir = i;
  2020. X                    }
  2021. X                }
  2022. X
  2023. X                /* Go that direction. */
  2024. X                if (best_dir == -1)
  2025. X                {
  2026. X                    /* No direction to go.  Turn around. */
  2027. X                    best_dir = turn_around (robot_face);
  2028. X                }
  2029. X#ifdef DEBUG_FILE
  2030. X                else
  2031. X                {
  2032. X                    fprintf (debugFile, "Best direction is ");
  2033. X                    switch (best_dir)
  2034. X                    {
  2035. X                        case north:
  2036. X                            fprintf (debugFile, "north\n");
  2037. X                            break;
  2038. X                        case east:
  2039. X                            fprintf (debugFile, "east\n");
  2040. X                            break;
  2041. X                        case south:
  2042. X                            fprintf (debugFile, "south\n");
  2043. X                            break;
  2044. X                        case west:
  2045. X                            fprintf (debugFile, "west\n");
  2046. X                            break;
  2047. X                        default:
  2048. X                            debug ("Switch blah!");
  2049. X                    }
  2050. X                    fprintf (debugFile, "Enemies seen: %d\n",
  2051. X                        best_node->enemies_seen);
  2052. X                    fprintf (debugFile, "Enemies suspected: %d\n",
  2053. X                        best_node->enemies_suspected);
  2054. X                    fprintf (debugFile, "Mines seen: %d\n",
  2055. X                        best_node->mines_seen);
  2056. X                    fprintf (debugFile, "Lowest time: %ld\n",
  2057. X                        best_node->lowest_time_last_seen);
  2058. X                    fprintf (debugFile, "Path length: %d\n",
  2059. X                        best_node->distance_to_target);
  2060. X                }
  2061. X                fprintf (debugFile, "\n");
  2062. X                fflush (debugFile);
  2063. X#endif DEBUG_FILE
  2064. X
  2065. X                /* Make our move. */
  2066. X
  2067. X                /* If there's no best move, turn around. */
  2068. X                if (best_node == NULL)
  2069. X                    our_cmd = turn[turn_around(robot_face)];
  2070. X
  2071. X                /* If there are no enemies/suspected enemies in
  2072. X                   the best path, and we're not cloaked, and we're
  2073. X                   not scanning, and we have at least 5 charges,
  2074. X                   then scan. */
  2075. X                /* else if (best_node->enemies_seen == 0
  2076. X                && best_node->enemies_suspected == 0
  2077. X                && robot_stats.cloak == 0
  2078. X                && robot_stats.scan == 0
  2079. X                && robot_stats.ammo >= 5)
  2080. X                    our_cmd = 's'; */
  2081. X
  2082. X                /* Otherwise, turn & move in the best direction. */
  2083. X                else if (robot_face != best_dir && !must_escape)
  2084. X                    our_cmd = turn[best_dir];
  2085. X                else our_cmd = move[best_dir];
  2086. X            }
  2087. X
  2088. X            /* Do what's best. */
  2089. X            send_char (our_cmd);
  2090. X        }
  2091. X    }
  2092. X
  2093. X    /* This gets called by longjmp(). */
  2094. X    else
  2095. X    {
  2096. X        /* We've been told to quit. */
  2097. X        return;
  2098. X    }
  2099. X}
  2100. X
  2101. X# endif ROBOT
  2102. END_OF_FILE
  2103. if test 42868 -ne `wc -c <'robot.c'`; then
  2104.     echo shar: \"'robot.c'\" unpacked with wrong size!
  2105. fi
  2106. # end of 'robot.c'
  2107. fi
  2108. echo shar: End of archive 1 \(of 4\).
  2109. cp /dev/null ark1isdone
  2110. MISSING=""
  2111. for I in 1 2 3 4 ; do
  2112.     if test ! -f ark${I}isdone ; then
  2113.     MISSING="${MISSING} ${I}"
  2114.     fi
  2115. done
  2116. if test "${MISSING}" = "" ; then
  2117.     echo You have unpacked all 4 archives.
  2118.     rm -f ark[1-9]isdone
  2119. else
  2120.     echo You still need to unpack the following archives:
  2121.     echo "        " ${MISSING}
  2122. fi
  2123. ##  End of shell archive.
  2124. exit 0
  2125.