home *** CD-ROM | disk | FTP | other *** search
- Path: uunet!news.tek.com!master!saab!billr
- From: billr@saab.CNA.TEK.COM (Bill Randle)
- Newsgroups: comp.sources.games
- Subject: v15i032: robot_hunt - original hunt with a robot, Part01/04
- Message-ID: <4188@master.CNA.TEK.COM>
- Date: 14 Jan 93 03:13:13 GMT
- Sender: news@master.CNA.TEK.COM
- Lines: 2113
- Approved: billr@saab.CNA.TEK.COM
- Xref: uunet comp.sources.games:1531
-
- Submitted-by: whatis@ucsd.edu (Steve Boswell)
- Posting-number: Volume 15, Issue 32
- Archive-name: robot_hunt/Part01
- Environment: Curses, Sockets
-
- [This was previously posted in alt.sources. It is being posted here so that
- it may enjoy a permanent, archived home. -br]
-
- [[From the author:
- I've been sitting on this source code for too long. This is the
- original version of hunt, with a hunt robot. It uses a breadth-first
- search to discover the best action it can do at every step.
-
- I hesitated to release it because it still had a few peculiarities, but
- they're minor, and besides, the robot is already a skilled opponent.
-
- I'll release better versions of it at irregular intervals.
-
- Enjoy! (His name is Minotaur, by the way. :-)
-
- Comments, questions, and large sums of money can be sent to:
-
- Steve Boswell
- whatis@ucsd.edu
- whatis@gnu.ai.mit.edu
- ]]
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 1 (of 4)."
- # Contents: README MANIFEST expl.c player.h robot.c
- # Wrapped by billr@saab on Wed Jan 13 19:04:32 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(859 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- XIf you have an old tcp/ip you might have to turn off the BROADCAST
- Xoption; see the Makefile.
- X
- XHunt is not officially supported by anyone anywhere; however, bug
- Xreports will be read and bug fixes/enhancements may be sent out at
- Xirregular intervals. Enjoy.
- X
- X ucbvax!ucsfcgl!conrad
- X ucsfcgl!conrad@berkeley.edu
- X
- X---------------------------------------------------------------------
- X
- XNew addition as of 29-Nov-92:
- X
- XThere is now a hunt robot. It mostly works, but sometimes it gets into
- Xsteady states & so forth. A couple of bugs involving differences
- Xbetween BSD 4.2 and 4.3 (mostly with sockets getting reused after
- Xthey've closed) have been fixed. See the man page for more details.
- X
- XI will sort of support the hunt robot, in that if you find a bug in
- Xit, I'll incorporate the fix into the next release.
- X
- XSteve Boswell
- Xwhatis@ucsd.edu
- Xwhatis@gnu.ai.mit.edu
- END_OF_FILE
- if test 859 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'MANIFEST' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'MANIFEST'\"
- else
- echo shar: Extracting \"'MANIFEST'\" \(734 characters\)
- sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
- X File Name Archive # Description
- X-----------------------------------------------------------
- X MANIFEST 1 This shipping list
- X Makefile 4
- X README 1
- X answer.c 3
- X connect.c 4
- X draw.c 3
- X driver.c 2
- X execute.c 3
- X expl.c 1
- X extern.c 2
- X hunt.6 3
- X hunt.c 2
- X hunt.h 3
- X makemaze.c 4
- X pathname.c 4
- X player.h 1
- X playit.c 3
- X robot.c 1
- X shots.c 2
- X terminal.c 4
- END_OF_FILE
- if test 734 -ne `wc -c <'MANIFEST'`; then
- echo shar: \"'MANIFEST'\" unpacked with wrong size!
- fi
- # end of 'MANIFEST'
- fi
- if test -f 'expl.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'expl.c'\"
- else
- echo shar: Extracting \"'expl.c'\" \(4898 characters\)
- sed "s/^X//" >'expl.c' <<'END_OF_FILE'
- X/*
- X * Copyright (c) 1985 Regents of the University of California.
- X * All rights reserved.
- X *
- X * Redistribution and use in source and binary forms are permitted
- X * provided that the above copyright notice and this paragraph are
- X * duplicated in all such forms and that any documentation,
- X * advertising materials, and other materials related to such
- X * distribution and use acknowledge that the software was developed
- X * by the University of California, Berkeley. The name of the
- X * University may not be used to endorse or promote products derived
- X * from this software without specific prior written permission.
- X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- X */
- X
- X#ifndef lint
- Xstatic char sccsid[] = "@(#)expl.c 5.2 (Berkeley) 6/27/88";
- X#endif /* not lint */
- X
- X/*
- X * Hunt
- X * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
- X * San Francisco, California
- X */
- X
- X# include "hunt.h"
- X
- X/*
- X * showexpl:
- X * Show the explosions as they currently are
- X */
- Xshowexpl(y, x, type)
- Xregister int y, x;
- Xchar type;
- X{
- X register PLAYER *pp;
- X register EXPL *ep;
- X
- X if (y < 0 || y >= HEIGHT)
- X return;
- X if (x < 0 || x >= WIDTH)
- X return;
- X ep = (EXPL *) malloc(sizeof (EXPL)); /* NOSTRICT */
- X ep->e_y = y;
- X ep->e_x = x;
- X ep->e_char = type;
- X ep->e_next = Expl[0];
- X Expl[0] = ep;
- X for (pp = Player; pp < End_player; pp++) {
- X if (pp->p_maze[y][x] == type)
- X continue;
- X pp->p_maze[y][x] = type;
- X cgoto(pp, y, x);
- X outch(pp, type);
- X }
- X# ifdef MONITOR
- X for (pp = Monitor; pp < End_monitor; pp++) {
- X if (pp->p_maze[y][x] == type)
- X continue;
- X pp->p_maze[y][x] = type;
- X cgoto(pp, y, x);
- X outch(pp, type);
- X }
- X# endif MONITOR
- X switch (Maze[y][x]) {
- X case WALL1:
- X case WALL2:
- X case WALL3:
- X# ifdef RANDOM
- X case DOOR:
- X# endif RANDOM
- X# ifdef REFLECT
- X case WALL4:
- X case WALL5:
- X# endif REFLECT
- X if (y >= UBOUND && y < DBOUND && x >= LBOUND && x < RBOUND)
- X remove_wall(y, x);
- X break;
- X }
- X}
- X
- X/*
- X * rollexpl:
- X * Roll the explosions over, so the next one in the list is at the
- X * top
- X */
- Xrollexpl()
- X{
- X register EXPL *ep;
- X register PLAYER *pp;
- X register int y, x;
- X register char c;
- X register EXPL *nextep;
- X
- X for (ep = Expl[EXPLEN - 1]; ep != NULL; ep = nextep) {
- X nextep = ep->e_next;
- X y = ep->e_y;
- X x = ep->e_x;
- X if (y < UBOUND || y >= DBOUND || x < LBOUND || x >= RBOUND)
- X c = Maze[y][x];
- X else
- X c = SPACE;
- X for (pp = Player; pp < End_player; pp++)
- X if (pp->p_maze[y][x] == ep->e_char) {
- X pp->p_maze[y][x] = c;
- X cgoto(pp, y, x);
- X outch(pp, c);
- X }
- X# ifdef MONITOR
- X for (pp = Monitor; pp < End_monitor; pp++)
- X check(pp, y, x);
- X# endif MONITOR
- X free((char *) ep);
- X }
- X for (x = EXPLEN - 1; x > 0; x--)
- X Expl[x] = Expl[x - 1];
- X Expl[0] = NULL;
- X}
- X
- X/* There's about 700 walls in the initial maze. So we pick a number
- X * that keeps the maze relatively full. */
- X# define MAXREMOVE 40
- X
- Xstatic REGEN removed[MAXREMOVE];
- Xstatic REGEN *rem_index = removed;
- X
- X/*
- X * remove_wall - add a location where the wall was blown away.
- X * if there is no space left over, put the a wall at
- X * the location currently pointed at.
- X */
- Xremove_wall(y, x)
- Xint y, x;
- X{
- X register REGEN *r;
- X# if defined(MONITOR) || defined(FLY)
- X register PLAYER *pp;
- X# endif MONITOR || FLY
- X# ifdef FLY
- X register char save_char;
- X# endif FLY
- X
- X r = rem_index;
- X while (r->r_y != 0) {
- X# ifdef FLY
- X switch (Maze[r->r_y][r->r_x]) {
- X case SPACE:
- X case LEFTS:
- X case RIGHT:
- X case ABOVE:
- X case BELOW:
- X case FLYER:
- X save_char = Maze[r->r_y][r->r_x];
- X goto found;
- X }
- X# else FLY
- X if (Maze[r->r_y][r->r_x] == SPACE)
- X break;
- X# endif FLY
- X if (++r >= &removed[MAXREMOVE])
- X r = removed;
- X }
- X
- Xfound:
- X if (r->r_y != 0) {
- X /* Slot being used, put back this wall */
- X# ifdef FLY
- X if (save_char == SPACE)
- X Maze[r->r_y][r->r_x] = Orig_maze[r->r_y][r->r_x];
- X else {
- X pp = play_at(r->r_y, r->r_x);
- X if (pp->p_flying >= 0)
- X pp->p_flying += rand_num(10);
- X else {
- X pp->p_flying = rand_num(20);
- X pp->p_flyx = 2 * rand_num(6) - 5;
- X pp->p_flyy = 2 * rand_num(6) - 5;
- X }
- X pp->p_over = Orig_maze[r->r_y][r->r_x];
- X pp->p_face = FLYER;
- X Maze[r->r_y][r->r_x] = FLYER;
- X showexpl(r->r_y, r->r_x, FLYER);
- X }
- X# else FLY
- X Maze[r->r_y][r->r_x] = Orig_maze[r->r_y][r->r_x];
- X# endif FLY
- X# ifdef RANDOM
- X if (rand_num(100) == 0)
- X Maze[r->r_y][r->r_x] = DOOR;
- X# endif RANDOM
- X# ifdef REFLECT
- X if (rand_num(100) == 0) /* one percent of the time */
- X Maze[r->r_y][r->r_x] = WALL4;
- X# endif REFLECT
- X# ifdef MONITOR
- X for (pp = Monitor; pp < End_monitor; pp++)
- X check(pp, r->r_y, r->r_x);
- X# endif MONITOR
- X }
- X
- X r->r_y = y;
- X r->r_x = x;
- X if (++r >= &removed[MAXREMOVE])
- X rem_index = removed;
- X else
- X rem_index = r;
- X
- X Maze[y][x] = SPACE;
- X# ifdef MONITOR
- X for (pp = Monitor; pp < End_monitor; pp++)
- X check(pp, y, x);
- X# endif MONITOR
- X}
- END_OF_FILE
- if test 4898 -ne `wc -c <'expl.c'`; then
- echo shar: \"'expl.c'\" unpacked with wrong size!
- fi
- # end of 'expl.c'
- fi
- if test -f 'player.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'player.h'\"
- else
- echo shar: Extracting \"'player.h'\" \(284 characters\)
- sed "s/^X//" >'player.h' <<'END_OF_FILE'
- X/* Stuff needed by both playit.c and robot.c */
- X
- Xextern char screen[24][80], blanks[80];
- Xextern int cur_row, cur_col;
- X
- X# undef CTRL
- X# define CTRL(x) ('x' & 037)
- X
- X#define GETCHR(fd) (--(fd)->_cnt >= 0 ? *(fd)->_ptr++&0377 : getchr(fd))
- X
- Xextern void setup_to_play();
- Xextern FILE *inf;
- END_OF_FILE
- if test 284 -ne `wc -c <'player.h'`; then
- echo shar: \"'player.h'\" unpacked with wrong size!
- fi
- # end of 'player.h'
- fi
- if test -f 'robot.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'robot.c'\"
- else
- echo shar: Extracting \"'robot.c'\" \(42868 characters\)
- sed "s/^X//" >'robot.c' <<'END_OF_FILE'
- X# ifdef ROBOT
- X
- X#include "hunt.h"
- X#include "player.h"
- X#include <sys/time.h>
- X#include <errno.h>
- X#include <setjmp.h>
- X
- X/* Used for debugging. */
- X#define debug(str) { long _l; leave (-1, str); _l = *(long *)(-1); }
- X/* #define debug(str) */
- X
- X#ifdef DEBUG_FILE
- Xstatic FILE *debugFile;
- X#endif DEBUG_FILE
- X
- X/* How long we wait for volcano information to decay. */
- X#define VOLCANO_DECAY 5
- X
- X/* How far away from volcanos we should stay. */
- X#define VOLCANO_DISTANCE 5
- X
- X/* How long we wait for in-range information to decay. */
- X#define IN_RANGE_DECAY 1
- X
- X/* How far in front of an enemy is considered "in range". */
- X#define IN_RANGE_DISTANCE BULSPD * 2
- X
- X/* How long we wait for ammo information to decay. */
- X#define AMMO_DECAY 3
- X
- X/* How long we wait for 'enemy suspected' info to decay. */
- X#define ENEMY_DECAY 25
- X
- X/* The maximum number of walls we'll shoot through to get to
- X an enemy. */
- X#define MAX_THRU_WALLS 4
- X
- X/* Directions. */
- X#define north 0
- X#define east 1
- X#define south 2
- X#define west 3
- X
- X/* Maps DirectionType to turning command character. */
- Xchar turn[4] = { 'K', 'L', 'J', 'H' };
- X
- X/* Maps DirectionType to moving command character. */
- Xchar move[4] = { 'k', 'l', 'j', 'h' };
- X
- X/* Maps DirectionType to x-move and y-move. */
- Xint dir_to_xm[4] = { 0, 1, 0, -1 };
- Xint dir_to_ym[4] = { -1, 0, 1, 0 };
- X#define turn_around(d) \
- X ((d + 2) % 4)
- X
- X/* Neighbor information for BFS nodes. */
- X#define BFS_WALL 0
- X#define BFS_PRED 1
- X#define BFS_SUCC 2
- X
- X/* Holds information about each location in the maze. This info
- X is generated by a breadth-first search. */
- Xtypedef struct bfs_node bfs_node, *bfs_node_ptr;
- Xstruct bfs_node
- X{
- X /* Fields specifying how desirable this path is. */
- X
- X char enemies_seen;
- X /* Enemies actually seen along this path. */
- X char enemies_suspected;
- X /* Enemies suspected to be along this path. */
- X short mines_seen;
- X /* The amount of ammo we gain along this path. */
- X long lowest_time_last_seen;
- X /* The time we saw the area we haven't seen in the longest
- X time along this path. */
- X short distance_to_target;
- X /* How far we are from the path's best target. */
- X
- X /* Fields specifying what we saw at this exact location. */
- X
- X long time_last_seen;
- X /* The turn # that this node was seen last. */
- X short enemy_seen_decay;
- X /* If an enemy is suspected to be here, this number is
- X greater than zero, and is decremented every turn.
- X If this number is zero, no enemy is suspected here. */
- X short danger_seen_decay;
- X /* If this area is deemed dangerous (e.g. flying ammo, lava)
- X then this number is greater than zero, and is decremented
- X every turn. If this is zero, this area is not dangerous. */
- X
- X /* Fields specifying our position in the BFS paths. */
- X
- X char successors;
- X /* The number of successors we have to wait to be done
- X before we can get done. */
- X char neighbors[4];
- X /* Indexed by direction. 0 == Wall, 1 == Predecessor,
- X 2 == Successor. */
- X
- X /* Fields specifying our bookkeeping info. */
- X
- X char visited;
- X /* Nonzero if this location has been visited. */
- X char in_to_do_queue;
- X /* Nonzero if this location is in the "to do" queue. */
- X short next_x, next_y;
- X /* The next node in the "to do" or "path end" queue. */
- X};
- X
- X/* Holds info about our enemies. */
- Xtypedef struct
- X{
- X char name[NAMELEN];
- X /* Our enemy's name. */
- X int vis_state;
- X /* 0 == none, 1 == scanning, 2 == cloaking, -1 == must be read
- X from the screen. */
- X float score;
- X /* Their score. */
- X} enemy, *enemy_ptr;
- X
- X/* Holds info about the robot's statistics, as displayed on the
- X right side of the screen. */
- Xtypedef struct
- X{
- X char name[NAMELEN];
- X /* Our name. If name[0] == '\0', re-read it from the screen. */
- X int ammo;
- X /* Ammo left. If -1, re-read it from the screen. */
- X int scan;
- X /* -1 == re-read it from the screen, 0 == not scanning,
- X 1 == scanning. */
- X int cloak;
- X /* -1 == re-read it from the screen, 0 == not cloaking,
- X 1 == cloaking. */
- X int gun;
- X /* -1 == re-read it from the screen, 0 == not OK,
- X 1 == OK. */
- X int curr_damage;
- X /* Current hit points. If -1, re-read it from the screen. */
- X int tot_damage;
- X /* Total hit points possible. If -1, re-read it from the
- X screen. */
- X int kills;
- X /* Number of kills we have. If -1, re-read it from the
- X screen. */
- X enemy enemies[MAXPL - 1];
- X /* Our enemies. */
- X} screen_stats, *screen_stats_ptr;
- X
- X/* Robot data. (In most cases, a value of -1 means "unknown".) */
- X
- Xint robot_player; /* Nonzero if this client is a robot */
- Xint daemon_player; /* Nonzero if this client is a daemon too */
- Xint robot_x; /* Horizontal position of robot */
- Xint robot_y; /* Vertical position of robot */
- Xint robot_face; /* Which way the robot is facing */
- Xunsigned long robot_time=1; /* Robot's internal clock */
- Xscreen_stats robot_stats; /* Our statistics. */
- X
- X/* Tracks playing-field changes that affect the robot's behavior. */
- Xstatic bfs_node maze[HEIGHT + 1][WIDTH + 1];
- X
- X/* Keeps track of an enemy within killing distance, in
- X each direction. */
- Xtypedef struct
- X{
- X int distance;
- X /* How far away he is. 0 == no enemy this way. */
- X int walls;
- X /* How many shootable walls are between us. */
- X} active_enemy, active_enemy_ptr;
- X
- X/* Our active enemies, one for each direction. */
- Xstatic active_enemy active_enemies[4];
- X
- X/* Needed for the breadth-first search. */
- X
- Xstatic int to_do_head_x = -1, to_do_head_y, to_do_tail_x,
- X to_do_tail_y;
- X /* The "to do" queue. */
- Xstatic int path_end_head_x = -1, path_end_head_y, path_end_tail_x,
- X path_end_tail_y;
- X /* The "path end" queue. */
- X
- Xjmp_buf robot_jbuf; /* Used to (q)uit instantly */
- X
- X/* Returns -1 if the number is negative, 1 if the number is
- X positive, and 0 if it is 0. */
- Xstatic int
- Xsgn (number)
- Xint number;
- X{
- X if (number > 0)
- X return 1;
- X else if (number < 0)
- X return -1;
- X else return 0;
- X}
- X
- X/* Print a message in the status line (bottom of the screen.) */
- Xstatic void
- Xmessage (msg)
- Xchar *msg;
- X{
- X if (!daemon_player)
- X {
- X int old_cur_row, old_cur_col;
- X
- X old_cur_row = cur_row;
- X old_cur_col = cur_col;
- X mvcur (cur_row, cur_col, 23, 0);
- X cur_row = 23;
- X cur_col = 0;
- X put_str (msg);
- X clear_eol();
- X fflush (stdout);
- X mvcur (cur_row, cur_col, old_cur_row, old_cur_col);
- X cur_row = old_cur_row;
- X cur_col = old_cur_col;
- X }
- X}
- X
- X/* Returns nonzero if the given char is a wall. */
- Xstatic int
- Xis_a_wall (ch)
- Xchar ch;
- X{
- X return
- X (
- X ch == WALL1
- X || ch == WALL2
- X || ch == WALL3
- X# ifdef REFLECT
- X || ch == WALL4
- X || ch == WALL5
- X# endif REFLECT
- X );
- X}
- X
- X/* Map a player direction character to a direction. */
- Xstatic int
- Xplayer_char_to_direction (ch)
- Xunsigned char ch;
- X{
- X switch (ch)
- X {
- X case ABOVE:
- X case PLAYER_ABOVE:
- X return north;
- X
- X case BELOW:
- X case PLAYER_BELOW:
- X return south;
- X
- X case LEFTS:
- X case PLAYER_LEFT:
- X return west;
- X
- X case RIGHT:
- X case PLAYER_RIGHT:
- X return east;
- X
- X default:
- X debug ("player_char_to_direction failed");
- X }
- X}
- X
- X/* Mark a straight hallway as dangerous. */
- Xvoid
- Xdangerous_hall (danger_y, danger_x, danger_face, how_far, how_bad)
- Xint danger_y, danger_x, danger_face, how_far, how_bad;
- X{
- X int xm = dir_to_xm[danger_face];
- X int ym = dir_to_ym[danger_face];
- X
- X /* Mark everything in the hall dangerous, up to the first wall or
- X terra incognita. */
- X do
- X {
- X /* Mark here dangerous. */
- X if (maze[danger_y][danger_x].danger_seen_decay < how_bad)
- X maze[danger_y][danger_x].danger_seen_decay = how_bad;
- X
- X /* Move down the hall. */
- X danger_x += xm;
- X danger_y += ym;
- X
- X /* Remember how far we've gone. */
- X how_far--;
- X
- X /* Stop at the first wall or terra
- X incognita. */
- X } while (how_far > 0 &&
- X maze[danger_y][danger_x].time_last_seen != 0
- X && !is_a_wall (screen[danger_y][danger_x]));
- X}
- X
- X/* Gather information. */
- Xstatic void
- Xrobot_see (ch)
- Xunsigned char ch;
- X{
- X /* Very retentive debugging checks. */
- X if (path_end_head_x != -1)
- X debug ("path end queue has members before robot_see");
- X if (to_do_head_x != -1)
- X debug ("to do queue has members before robot_see");
- X
- X /* Distinguish between changes in the arena & status area. */
- X if (cur_row <= HEIGHT - 1)
- X {
- X if (cur_col <= WIDTH)
- X {
- X /* Handle changes in the arena. */
- X
- X /* If we've never seen this area before, we have now. */
- X if (!is_a_wall (screen[cur_row][cur_col]))
- X maze[cur_row][cur_col].time_last_seen = robot_time;
- X
- X /* Keep track of what's disappearing. */
- X switch (screen[cur_row][cur_col])
- X {
- X case DOOR:
- X case WALL1:
- X case WALL2:
- X case WALL3:
- X case WALL4:
- X case WALL5:
- X /* A wall disappeared. */
- X break;
- X
- X case KNIFE:
- X case SHOT:
- X case GRENADE:
- X case SATCHEL:
- X case BOMB:
- X case SLIME:
- X# ifdef VOLCANO
- X case LAVA:
- X# endif VOLCANO
- X /* Something deadly disappeared. We'll let the
- X decay counter tell us when it's really gone. */
- X break;
- X
- X case MINE:
- X case GMINE:
- X /* A mine disappeared. We'll notice this during
- X the BFS. */
- X break;
- X
- X case PLAYER_ABOVE:
- X case PLAYER_BELOW:
- X case PLAYER_RIGHT:
- X case PLAYER_LEFT:
- X /* We were just undrawn. Now we don't know what
- X way we're facing. */
- X robot_face = -1;
- X break;
- X
- X case ABOVE:
- X case BELOW:
- X case RIGHT:
- X case LEFTS:
- X /* An enemy disappeared. Remember that we saw
- X him here. */
- X maze[cur_row][cur_col].enemy_seen_decay
- X = ENEMY_DECAY;
- X break;
- X
- X case SPACE:
- X /* Something has moved into a space. We don't
- X do anything about this here. */
- X break;
- X
- X default:
- X /* Unrecognized character. Ignore it. */
- X break;
- X }
- X
- X /* Keep track of what's appearing. */
- X switch (ch)
- X {
- X case DOOR:
- X case WALL1:
- X case WALL2:
- X case WALL3:
- X# ifdef REFLECT
- X case WALL4:
- X case WALL5:
- X# endif REFLECT
- X /* A wall just appeared. Mark the area underneath
- X it as terra incognita. */
- X maze[cur_row][cur_col].time_last_seen = 0;
- X break;
- X
- X case KNIFE:
- X case SHOT:
- X case GRENADE:
- X case SATCHEL:
- X case BOMB:
- X case SLIME:
- X# ifdef VOLCANO
- X case LAVA:
- X# endif VOLCANO
- X /* Either someone just fired or a weapon finished
- X its current move. Mark the entire effective
- X hallway as dangerous. */
- X {
- X int i; /* A direction to be marked. */
- X
- X /* Mark all directions dangerous. */
- X for (i = north; i <= west; i++)
- X dangerous_hall (cur_row, cur_col, i,
- X WIDTH / BULSPD, AMMO_DECAY);
- X }
- X break;
- X
- X case MINE:
- X case GMINE:
- X /* A new mine. Make a list of mines in the BFS. */
- X break;
- X
- X case PLAYER_ABOVE:
- X case PLAYER_BELOW:
- X case PLAYER_RIGHT:
- X case PLAYER_LEFT:
- X /* It's ourselves. Now we know where we are. */
- X robot_x = cur_col;
- X robot_y = cur_row;
- X robot_face = player_char_to_direction (ch);
- X break;
- X
- X case ABOVE:
- X case BELOW:
- X case RIGHT:
- X case LEFTS:
- X /* A player has been spotted. */
- X
- X /* Remember where he was. */
- X maze[cur_row][cur_col].enemy_seen_decay
- X = ENEMY_DECAY;
- X
- X /* Consider everything in front of him as
- X being dangerous. */
- X dangerous_hall (cur_row, cur_col,
- X player_char_to_direction (ch),
- X IN_RANGE_DISTANCE, IN_RANGE_DECAY);
- X break;
- X
- X case SPACE:
- X /* Something just disappeared. */
- X break;
- X
- X default:
- X /* Unrecognized character. Probably someone
- X flying. */
- X break;
- X }
- X }
- X else
- X {
- X /* Handle changes in the status area. For each stat
- X line where a change occurs, mark that stat as needing
- X to be re-read. */
- X switch (cur_row)
- X {
- X case STAT_NAME_ROW:
- X /* Our name has changed. Re-read it. */
- X robot_stats.name[0] = '\0';
- X break;
- X
- X case STAT_AMMO_ROW:
- X /* Our ammo count has changed. Re-read it. */
- X robot_stats.ammo = -1;
- X break;
- X
- X case STAT_SCAN_ROW:
- X /* Our scanning status has changed. Re-read it. */
- X robot_stats.scan = -1;
- X break;
- X
- X case STAT_CLOAK_ROW:
- X /* Our cloaking status has changed. Re-read it. */
- X robot_stats.cloak = -1;
- X break;
- X
- X case STAT_GUN_ROW:
- X /* Our gun's condition has changed. Re-read it. */
- X robot_stats.gun = -1;
- X break;
- X
- X case STAT_DAM_ROW:
- X /* Our damage status has changed. Re-read it. */
- X robot_stats.curr_damage = robot_stats.tot_damage
- X = -1;
- X break;
- X
- X case STAT_KILL_ROW:
- X /* Our number of kills has changed. Re-read it. */
- X robot_stats.kills = -1;
- X break;
- X
- X default:
- X /* See if the change was within the enemy list. */
- X if (cur_row >= STAT_PLAY_ROW + 1 && cur_row
- X < STAT_PLAY_ROW + MAXPL)
- X {
- X /* It was. Mark that enemy as needing to
- X be re-read from the screen. */
- X robot_stats.enemies[cur_row -
- X (STAT_PLAY_ROW + 1)].vis_state = -1;
- X }
- X
- X /* Otherwise, ignore the change. It's probably
- X a monitor change (which we don't track.) */
- X break;
- X }
- X }
- X }
- X
- X /* Print the new character to the screen. */
- X put_ch (ch);
- X}
- X
- X/* Given a direction to look in, mark everything in that direction as
- X having been seen now. */
- Xstatic void
- Xlook_down_hall (xm, ym)
- Xint xm,ym;
- X{
- X int x,y; /* Where we're looking */
- X char ch; /* What we found */
- X
- X /* Start where we are. */
- X x = robot_x;
- X y = robot_y;
- X ch = 0;
- X
- X while (1)
- X {
- X /* Move down the hallway, time-stamp everything. If we
- X thought any enemies were here, we know for sure now. */
- X maze[y][x].time_last_seen = robot_time;
- X x += xm;
- X y += ym;
- X
- X /* If this was a door, stop. Thus we see the door. */
- X if (ch == DOOR)
- X break;
- X
- X /* If we're at the end of the hall, or if we find a door,
- X stop. */
- X ch = screen[y][x];
- X if (is_a_wall (ch))
- X break;
- X }
- X}
- X
- X/* For the breadth-first search done in update_info(). Puts a
- X location onto the "to do" queue. */
- Xstatic void
- Xdo_node (y, x, pred_dir)
- Xint x, y, pred_dir;
- X{
- X bfs_node_ptr current;
- X int i;
- X
- X /* Find the current node. */
- X current = &(maze[y][x]);
- X
- X /* Set up the current node. */
- X current->next_x = current->next_y = -1;
- X current->in_to_do_queue = 1;
- X for (i = north; i <= west; i++)
- X current->neighbors[i] = ((i == pred_dir) ? BFS_PRED : BFS_WALL);
- X
- X /* If the queue is empty, this is easy. */
- X if (to_do_head_x == -1)
- X {
- X /* Start the queue. */
- X to_do_head_x = to_do_tail_x = x;
- X to_do_head_y = to_do_tail_y = y;
- X }
- X else
- X {
- X /* Put this at the end of the queue. */
- X maze[to_do_tail_y][to_do_tail_x].next_x = x;
- X maze[to_do_tail_y][to_do_tail_x].next_y = y;
- X to_do_tail_x = x;
- X to_do_tail_y = y;
- X }
- X}
- X
- X/* For the breadth-first search done in update_info(). Puts a
- X location onto the "path end" queue. */
- Xstatic void
- Xpath_end_node (current_y, current_x)
- Xint current_y, current_x;
- X{
- X bfs_node_ptr current;
- X int i;
- X
- X /* Set up the current node. */
- X current = &(maze[current_y][current_x]);
- X current->next_x = current->next_y = -1;
- X for (i = north; i <= west; i++)
- X if (current->neighbors[i] == BFS_SUCC)
- X current->neighbors[i] = BFS_WALL;
- X current->successors = 0;
- X
- X /* If the queue is empty, this is easy. */
- X if (path_end_head_x == -1)
- X {
- X /* Start the queue. */
- X path_end_head_x = path_end_tail_x = current_x;
- X path_end_head_y = path_end_tail_y = current_y;
- X }
- X else
- X {
- X /* Put this at the end of the queue. */
- X maze[path_end_tail_y][path_end_tail_x].next_x = current_x;
- X maze[path_end_tail_y][path_end_tail_x].next_y = current_y;
- X path_end_tail_x = current_x;
- X path_end_tail_y = current_y;
- X }
- X}
- X
- X/* Compare two nodes' optimality. */
- Xstatic int
- Xnode_compare (left, right)
- Xbfs_node_ptr left, right;
- X{
- X /* Compare by danger. */
- X if (left->danger_seen_decay < right->danger_seen_decay)
- X return -1;
- X else if (left->danger_seen_decay > right->danger_seen_decay)
- X return 1;
- X
- X /* Compare by enemies actually seen. */
- X if (left->enemies_seen > right->enemies_seen)
- X return -1;
- X else if (left->enemies_seen < right->enemies_seen)
- X return 1;
- X
- X /* Compare by enemies suspected. */
- X if (left->enemies_suspected > right->enemies_suspected)
- X return -1;
- X else if (left->enemies_suspected < right->enemies_suspected)
- X return 1;
- X
- X /* Compare by ammunition available. */
- X if (left->mines_seen > right->mines_seen)
- X return -1;
- X else if (left->mines_seen < right->mines_seen)
- X return 1;
- X
- X /* If we've seen anything (i.e. at least one of the stats
- X above is not zero) then these nodes are equal. Otherwise,
- X the robot gets into steady states. */
- X if (left->enemies_seen != 0
- X || right->enemies_seen != 0
- X || left->enemies_suspected != 0
- X || right->enemies_suspected != 0
- X || left->mines_seen != 0
- X || right->mines_seen != 0)
- X return 0;
- X
- X /* Compare by most aged area. */
- X if (left->lowest_time_last_seen < right->lowest_time_last_seen)
- X return -1;
- X else if (left->lowest_time_last_seen > right->lowest_time_last_seen)
- X return 1;
- X
- X /* Compare by distance from the robot. */
- X if (left->distance_to_target < right->distance_to_target)
- X return -1;
- X else if (left->distance_to_target > right->distance_to_target)
- X return 1;
- X
- X /* The two nodes are equal. */
- X return 0;
- X}
- X
- X/* Count the # of walls between ourself and the target, put the result
- X in "walls", put the distance to the target in "distance", and put
- X the direction the target is in in "dir". Return 0 if everything
- X looks fine, return 1 if there are unshootable walls between us and
- X the target, and return 2 if we & the target are not lined up. */
- Xstatic int
- Xwalls_between (y, x, walls, distance, dir)
- Xint y, x, *walls, *distance, *dir;
- X{
- X int xm, ym; /* The direction the target is from us */
- X int status; /* What we're finding */
- X
- X /* Set up to look. */
- X *distance = 0;
- X *walls = 0;
- X status = 0;
- X xm = sgn (robot_x - x);
- X ym = sgn (robot_y - y);
- X
- X /* If we're not directly aligned, return 2 now. */
- X if (xm != 0 && ym != 0)
- X return 2;
- X
- X /* Look at the entire path from here to there, count the
- X number of walls. */
- X while (x != robot_x || y != robot_y)
- X {
- X /* If this is a wall, record it. */
- X switch (screen[y][x])
- X {
- X case WALL1:
- X case WALL2:
- X case WALL3:
- X /* This is a wall we can shoot through. */
- X (*walls)++;
- X break;
- X
- X case DOOR:
- X#ifdef REFLECT
- X case WALL4:
- X case WALL5:
- X#endif REFLECT
- X /* This is a wall we can't shoot through. */
- X (*walls)++;
- X status = 1;
- X break;
- X
- X default:
- X /* We don't record anything else. */
- X break;
- X }
- X
- X /* Move along. */
- X x += xm;
- X y += ym;
- X (*distance)++;
- X }
- X
- X /* If there are too many walls, forget it. */
- X if ((*walls) > MAX_THRU_WALLS)
- X return 1;
- X
- X /* Save what direction the target is in. */
- X if (xm == 0 && ym == -1)
- X *dir = south;
- X else if (xm == 1 && ym == 0)
- X *dir = west;
- X else if (xm == 0 && ym == 1)
- X *dir = north;
- X else if (xm == -1 && ym == 0)
- X *dir = east;
- X else
- X debug ("Funky xm/ym");
- X
- X return status;
- X}
- X
- X/* Update our information about the playing field. */
- Xstatic void
- Xupdate_info()
- X{
- X unsigned char ch;
- X int x,y;
- X
- X /* Keep getting info from the driver until there isn't any.
- X Also make sure that we've reappeared. (We could be flying,
- X and there's no point in continuing until we know where we
- X are.) */
- X do
- X {
- X ch = GETCHR (inf);
- X
- X switch (ch & 0377)
- X {
- X case MOVE:
- X y = GETCHR(inf);
- X x = GETCHR(inf);
- X if (!daemon_player)
- X {
- X mvcur(cur_row, cur_col, y, x);
- X }
- X cur_row = y;
- X cur_col = x;
- X break;
- X case ADDCH:
- X ch = GETCHR(inf);
- X robot_see(ch);
- X break;
- X case CLRTOEOL:
- X clear_eol();
- X break;
- X case CLEAR:
- X clear_screen();
- X break;
- X case REFRESH:
- X fflush(stdout);
- X break;
- X case REDRAW:
- X redraw_screen();
- X fflush(stdout);
- X break;
- X case ENDWIN:
- X if ((ch = GETCHR(inf)) == LAST_PLAYER)
- X Last_player = TRUE;
- X ch = EOF;
- X /* Fall through */
- X
- X case EOF:
- X fflush(stdout);
- X (void) fclose (inf);
- X longjmp (robot_jbuf, 1);
- X /* NOTREACHED */
- X
- X case BELL:
- X if (!daemon_player)
- X {
- X putchar(CTRL(G));
- X }
- X break;
- X case READY:
- X (void) fflush(stdout);
- X (void) GETCHR (inf);
- X break;
- X default:
- X robot_see(ch);
- X break;
- X }
- X } while (ch != READY || robot_face == -1);
- X
- X /* Make sure all our statistics from the right side of the screen
- X are up to date. */
- X
- X /* Check our name. */
- X if (robot_stats.name[0] == '\0')
- X sscanf (&(screen[STAT_NAME_ROW][STAT_LABEL_COL]), "%-13.13s",
- X robot_stats.name);
- X
- X /* Check our ammo. */
- X if (robot_stats.ammo == -1)
- X sscanf (&(screen[STAT_AMMO_ROW][STAT_VALUE_COL]), "%3d",
- X &(robot_stats.ammo));
- X
- X /* Check our scanning status. (It's faster to just update it
- X than check it first.) */
- X robot_stats.scan = (screen[STAT_SCAN_ROW][STAT_VALUE_COL + 1]
- X == 'o') ? 1 : 0;
- X
- X /* Check our cloaking status. (It's faster to just update it
- X than check it first.) */
- X robot_stats.cloak = (screen[STAT_CLOAK_ROW][STAT_VALUE_COL + 1]
- X == 'o') ? 1 : 0;
- X
- X /* Check our gun's status. (It's faster to just update it
- X than check it first.) */
- X robot_stats.gun = (screen[STAT_GUN_ROW][STAT_VALUE_COL + 1]
- X == 'o') ? 1 : 0;
- X
- X /* Check our current/total hit points. */
- X if (robot_stats.curr_damage == -1 || robot_stats.tot_damage == -1)
- X sscanf (&(screen[STAT_DAM_ROW][STAT_VALUE_COL]), "%2d/%2d",
- X &(robot_stats.curr_damage), &(robot_stats.tot_damage));
- X
- X /* Check our kill count. */
- X if (robot_stats.kills == -1)
- X sscanf (&(screen[STAT_KILL_ROW][STAT_VALUE_COL]), "%3d",
- X &(robot_stats.kills));
- X
- X /* Check each of our enemies. */
- X#ifdef CHECK_ENEMIES
- X {
- X int i;
- X
- X for (i = 0; i < MAXPL; i++)
- X {
- X char new_vis; /* Enemy's new visibility state. */
- X
- X /* Check that enemy. */
- X if (robot_stats.enemies[i].vis_state == -1)
- X {
- X if (screen[STAT_PLAY_ROW + 1 + i][STAT_NAME_COL] != ' ')
- X {
- X /* Update that enemy. */
- X sscanf (&(screen[STAT_PLAY_ROW + 1 + i]
- X [STAT_NAME_COL]), "%5.2f%c%-10.10s",
- X &(robot_stats.enemies[i].score),
- X &new_vis,
- X robot_stats.enemies[i].name);
- X switch (new_vis)
- X {
- X case '+':
- X robot_stats.enemies[i].vis_state = 1;
- X break;
- X case '*':
- X robot_stats.enemies[i].vis_state = 2;
- X break;
- X case ' ':
- X robot_stats.enemies[i].vis_state = 0;
- X break;
- X default:
- X debug ("Illegal enemy vis_state");
- X }
- X }
- X else
- X {
- X /* There's no enemy here any more. */
- X robot_stats.enemies[i].name[0] = '\0';
- X }
- X }
- X }
- X }
- X#endif CHECK_ENEMIES
- X
- X /* Advance one time unit. */
- X robot_time++;
- X
- X#ifdef DEBUG_FILE
- X {
- X char msg[60];
- X
- X fprintf (debugFile, "Turn #%ld\n-----------\n", robot_time);
- X fflush (debugFile);
- X sprintf (msg, "%ld", robot_time);
- X message (msg);
- X fflush (stdout);
- X }
- X#endif DEBUG_FILE
- X
- X /* Look around us, update our knowledge of the area. */
- X
- X /* Look up, if we can. */
- X if (robot_face != south)
- X look_down_hall (0, -1);
- X
- X /* Look down, if we can. */
- X if (robot_face != north)
- X look_down_hall (0, 1);
- X
- X /* Look right, if we can. */
- X if (robot_face != west)
- X look_down_hall (1, 0);
- X
- X /* Look left, if we can. */
- X if (robot_face != east)
- X look_down_hall (-1, 0);
- X
- X /* Before we do a breadth-first search, we must make sure
- X that the maze structure is correct. */
- X for (y = 0; y <= HEIGHT; y++)
- X {
- X for (x = 0; x <= WIDTH; x++)
- X {
- X bfs_node_ptr current;
- X
- X /* Check each node's correctness. */
- X current = &(maze[y][x]);
- X
- X if (current->visited != 0)
- X debug ("visited true before BFS");
- X if (current->in_to_do_queue != 0)
- X debug ("in_to_do_queue true before BFS");
- X if (current->successors != 0)
- X debug ("successors != 0 before BFS");
- X }
- X }
- X
- X /* Do a breadth-first search through the maze, find the best
- X action to do. */
- X if (to_do_head_x != -1)
- X debug ("to_do list isn't empty");
- X if (path_end_head_x != -1)
- X debug ("path_end list isn't empty");
- X
- X /* Start the "to do" queue with the robot's location.
- X (There is no predecessor where the robot is.) */
- X do_node (robot_y, robot_x, north);
- X maze[robot_y][robot_x].neighbors[north] = BFS_WALL;
- X#ifdef DEBUG_FILE
- X fprintf (debugFile, "Robot at (%d, %d)\n", robot_x, robot_y);
- X fflush (debugFile);
- X#endif DEBUG_FILE
- X
- X /* Look ahead, find everything on the way. */
- X while (to_do_head_x != -1)
- X {
- X bfs_node_ptr current;
- X int current_x, current_y;
- X int i;
- X
- X /* Pull a node off the "to do" list. */
- X current_x = to_do_head_x;
- X current_y = to_do_head_y;
- X to_do_head_x = maze[current_y][current_x].next_x;
- X to_do_head_y = maze[current_y][current_x].next_y;
- X current = &(maze[current_y][current_x]);
- X current->next_x = current->next_y = -1;
- X current->in_to_do_queue = 0;
- X
- X#ifdef DEBUG_FILE
- X fprintf (debugFile, "Visited (%d,%d)\n", current_x, current_y);
- X fflush (debugFile);
- X#endif DEBUG_FILE
- X
- X /* Make sure it hasn't been visited yet. */
- X if (current->visited == 1)
- X debug ("visit out of order");
- X current->visited = 1;
- X
- X /* Reset this node. */
- X current->enemies_seen = 0;
- X current->enemies_suspected = 0;
- X current->mines_seen = 0;
- X current->lowest_time_last_seen = robot_time + 1;
- X
- X /* If we've never seen this area, end the path here. */
- X if (current->time_last_seen == 0)
- X {
- X path_end_node (current_y, current_x);
- X#ifdef DEBUG_FILE
- X fprintf (debugFile,
- X "Path ended at (%d,%d) -- terra incognita\n",
- X current_x, current_y);
- X fflush (debugFile);
- X#endif DEBUG_FILE
- X goto toDoLoopEnd;
- X }
- X
- X /* Handle anything we can find in this pass. */
- X switch (screen[current_y][current_x])
- X {
- X# ifdef VOLCANO
- X case LAVA:
- X /* Volcano! Run back VOLCANO_DISTANCE steps and
- X set the danger to VOLCANO_DECAY. */
- X {
- X int how_far = VOLCANO_DISTANCE;
- X int danger_x, danger_y;
- X bfs_node_ptr danger_node;
- X
- X /* Start where the lava is, run backwards. */
- X danger_x = current_x;
- X danger_y = current_y;
- X while (--how_far >= 0)
- X {
- X int i; /* Used to find predecessor. */
- X
- X /* If we meet up with the robot, stop .*/
- X if (danger_x == robot_x && danger_y == robot_y)
- X break;
- X
- X /* Find the node. */
- X danger_node = &(maze[danger_y][danger_x]);
- X
- X /* Mark this area as dangerous. */
- X if (danger_node->danger_seen_decay
- X < VOLCANO_DECAY)
- X danger_node->danger_seen_decay
- X = VOLCANO_DECAY;
- X
- X /* Find the predecessor. */
- X for (i = north; i <= west; i++)
- X if (danger_node->neighbors[i] == BFS_PRED)
- X break;
- X if (i > west)
- X break;
- X
- X /* Move there. */
- X danger_x += dir_to_xm[i];
- X danger_y += dir_to_ym[i];
- X }
- X }
- X
- X /* Don't go any further. */
- X path_end_node (current_y, current_x);
- X#ifdef DEBUG_FILE
- X fprintf (debugFile,
- X "Path ended at (%d,%d) -- lava\n",
- X current_x, current_y);
- X fflush (debugFile);
- X#endif DEBUG_FILE
- X goto toDoLoopEnd;
- X# endif VOLCANO
- X
- X default:
- X break;
- X }
- X
- X /* Take all successors that aren't the predecessor and
- X remember to do them. */
- X for (i = north; i <= west; i++)
- X {
- X int new_x, new_y;
- X bfs_node_ptr successor;
- X
- X /* If this direction is the predecessor, don't look. */
- X if (current->neighbors[i] == BFS_PRED)
- X continue;
- X
- X /* Move into places we haven't been. */
- X new_x = current_x + dir_to_xm[i];
- X new_y = current_y + dir_to_ym[i];
- X successor = &(maze[new_y][new_x]);
- X
- X /* If we've moved into somewhere that's already been
- X visited, then we end the path here. */
- X if (successor->visited != 1
- X && successor->in_to_do_queue != 1
- X && !is_a_wall (screen[new_y][new_x]))
- X current->neighbors[i] = BFS_SUCC;
- X else current->neighbors[i] = BFS_WALL;
- X }
- X
- X /* Now that we know where our successors are, remember to
- X do them. */
- X for (i = north; i <= west; i++)
- X {
- X if (current->neighbors[i] == BFS_SUCC)
- X {
- X (current->successors)++;
- X do_node (current_y + dir_to_ym[i],
- X current_x + dir_to_xm[i], turn_around(i));
- X }
- X }
- X
- X /* If we didn't have any successors, end the path here. */
- X if (current->successors == 0)
- X {
- X path_end_node (current_y, current_x);
- X#ifdef DEBUG_FILE
- X fprintf (debugFile,
- X "Path ended at (%d,%d) -- dead end\n",
- X current_x, current_y);
- X fflush (debugFile);
- X#endif DEBUG_FILE
- X }
- X
- XtoDoLoopEnd:;
- X }
- X
- X /* Reset the "active enemy" list. */
- X {
- X int i;
- X
- X for (i = north; i <= west; i++)
- X active_enemies[i].distance = 0;
- X }
- X
- X /* Now process each path back to the robot, generate total
- X statistics. */
- X while (path_end_head_x != -1)
- X {
- X bfs_node_ptr current;
- X int current_x, current_y;
- X
- X /* Pull a node off the "path end" list. */
- X current_x = path_end_head_x;
- X current_y = path_end_head_y;
- X path_end_head_x = maze[current_y][current_x].next_x;
- X path_end_head_y = maze[current_y][current_x].next_y;
- X current = &(maze[current_y][current_x]);
- X current->next_x = current->next_y = -1;
- X
- X /* Run back along this path until we find more successors
- X than ourselves. */
- X while (1)
- X {
- X int predecessor;
- X int i;
- X int a_stat_dominated = 0;
- X /* Nonzero as soon as any stat has been dominated. */
- X
- X /* If this is the robot's node, skip it. */
- X if (current_x == robot_x && current_y == robot_y)
- X break;
- X
- X /* Un-mark the 'visited' flag on the way back. */
- X current = &(maze[current_y][current_x]);
- X#ifdef DEBUG_FILE
- X fprintf (debugFile, "Unvisited (%d,%d), time=%ld\n",
- X current_x, current_y, current->time_last_seen);
- X fflush (debugFile);
- X#endif DEBUG_FILE
- X if (current->visited == 0)
- X debug ("un-visit out of order");
- X current->visited = 0;
- X
- X /* Set up to be compared to successors. */
- X current->distance_to_target = 0;
- X
- X /* Figure in the statistics of our best successor. */
- X for (i = north; i <= west; i++)
- X {
- X int successor_x, successor_y;
- X bfs_node_ptr successor;
- X int dominated = 0;
- X /* Nonzero if one of the stats has already
- X dominated. We use this to set the distance. */
- X
- X /* Find our predecessor, while we're at it. */
- X if (current->neighbors[i] == BFS_PRED)
- X predecessor = i;
- X
- X /* Find the current successor. */
- X if (current->neighbors[i] != BFS_SUCC)
- X continue;
- X successor_x = current_x + dir_to_xm[i];
- X successor_y = current_y + dir_to_ym[i];
- X successor = &(maze[successor_y][successor_x]);
- X
- X /* Remember the most dominant of each stat. */
- X if (current->enemies_seen < successor->enemies_seen)
- X {
- X /* The successor's stat was better: remember it. */
- X current->enemies_seen = successor->enemies_seen;
- X
- X /* If we're the first stat to dominate, then
- X remember that successor's distance from the
- X robot. This way we find the first good thing
- X in our path, and don't ignore the less good
- X ones for the more desirable ones. */
- X if (a_stat_dominated == 0)
- X {
- X a_stat_dominated = 1;
- X dominated = 1;
- X current->distance_to_target
- X = successor->distance_to_target;
- X }
- X if (dominated == 0)
- X {
- X dominated = 1;
- X if (current->distance_to_target
- X > successor->distance_to_target)
- X current->distance_to_target
- X = successor->distance_to_target;
- X }
- X }
- X
- X if (current->enemies_suspected
- X < successor->enemies_suspected)
- X {
- X current->enemies_suspected
- X = successor->enemies_suspected;
- X if (a_stat_dominated == 0)
- X {
- X a_stat_dominated = 1;
- X dominated = 1;
- X current->distance_to_target
- X = successor->distance_to_target;
- X }
- X if (dominated == 0)
- X {
- X dominated = 1;
- X if (current->distance_to_target
- X > successor->distance_to_target)
- X current->distance_to_target
- X = successor->distance_to_target;
- X }
- X }
- X
- X if (current->mines_seen < successor->mines_seen)
- X {
- X current->mines_seen = successor->mines_seen;
- X if (a_stat_dominated == 0)
- X {
- X a_stat_dominated = 1;
- X dominated = 1;
- X current->distance_to_target
- X = successor->distance_to_target;
- X }
- X if (dominated == 0)
- X {
- X dominated = 1;
- X if (current->distance_to_target
- X > successor->distance_to_target)
- X current->distance_to_target
- X = successor->distance_to_target;
- X }
- X }
- X
- X if (current->lowest_time_last_seen
- X > successor->lowest_time_last_seen)
- X {
- X current->lowest_time_last_seen
- X = successor->lowest_time_last_seen;
- X /* This stat does not dominate other
- X stats as far as distance goes. */
- X }
- X }
- X
- X /* If no stat dominated, then allow the lowest
- X time last seen to dominate. */
- X if (!a_stat_dominated)
- X {
- X int i;
- X
- X /* None of the successor nodes dominated. Allow
- X lowest_time_last_seen to dominate. */
- X for (i = north; i <= west; i++)
- X {
- X int successor_x, successor_y;
- X bfs_node_ptr successor;
- X
- X /* Find the current successor. */
- X if (current->neighbors[i] != BFS_SUCC)
- X continue;
- X successor_x = current_x + dir_to_xm[i];
- X successor_y = current_y + dir_to_ym[i];
- X successor = &(maze[successor_y][successor_x]);
- X
- X if (current->lowest_time_last_seen
- X == successor->lowest_time_last_seen)
- X {
- X current->distance_to_target
- X = successor->distance_to_target;
- X break;
- X }
- X }
- X }
- X
- X /* Add a step. */
- X (current->distance_to_target)++;
- X
- X /* Add in its local statistics. */
- X
- X /* Figure in the last time this area was seen. */
- X if (current->time_last_seen
- X < current->lowest_time_last_seen)
- X {
- X current->lowest_time_last_seen
- X = current->time_last_seen;
- X current->distance_to_target = 0;
- X }
- X
- X /* Figure in enemy's suspected locations. */
- X if (current->enemy_seen_decay > 0)
- X {
- X (current->enemies_suspected)++;
- X current->distance_to_target = 0;
- X }
- X
- X /* Figure in what's on the screen here. */
- X switch (screen[current_y][current_x])
- X {
- X case MINE:
- X /* There's a mine here. Count it up. */
- X current->mines_seen += BULREQ;
- X current->distance_to_target = 0;
- X break;
- X
- X case GMINE:
- X /* There's a mine here. Count it up. */
- X current->mines_seen += GRENREQ;
- X current->distance_to_target = 0;
- X break;
- X
- X case ABOVE:
- X case BELOW:
- X case RIGHT:
- X case LEFTS:
- X {
- X int target_dist;
- X /* Distance between us & enemy. */
- X int target_walls;
- X /* Shootable walls between us & enemy. */
- X int target_dir;
- X /* Direction enemy is in. */
- X
- X /* An enemy is here. Count it up. */
- X (current->enemies_seen)++;
- X current->distance_to_target = 0;
- X
- X /* If this enemy is within killing distance,
- X go for it. */
- X if (walls_between (current_y, current_x,
- X &target_walls, &target_dist, &target_dir) == 0)
- X {
- X int best_dist;
- X
- X /* If this enemy is the closest to us on
- X this side, remember him. */
- X best_dist = active_enemies[target_dir].distance;
- X if (best_dist == 0 || best_dist > target_dist)
- X {
- X active_enemies[target_dir].distance
- X = target_dist;
- X active_enemies[target_dir].walls
- X = target_walls;
- X }
- X }
- X break;
- X }
- X
- X default:
- X break;
- X }
- X
- X /* Move to our predecessor. If it has more successors
- X than us, get a new path end. */
- XmoveToPred:
- X current_x += dir_to_xm[predecessor];
- X current_y += dir_to_ym[predecessor];
- X (maze[current_y][current_x].successors)--;
- X if (maze[current_y][current_x].successors != 0)
- X break;
- X if (maze[current_y][current_x].next_x != -1)
- X debug ("mixup in backward path following");
- X }
- X }
- X maze[robot_y][robot_x].visited = 0; /* The un-base case. */
- X
- X /* Now we've generated the overall results of moving in each
- X legal direction. Decay all our suspicions. */
- X for (y = 0; y <= HEIGHT; y++)
- X {
- X for (x = 0; x <= WIDTH; x++)
- X {
- X bfs_node_ptr current = &(maze[y][x]);
- X
- X /* Decay our suspected enemy locations. */
- X if (current->enemy_seen_decay != 0)
- X (current->enemy_seen_decay)--;
- X
- X /* Decay our suspected danger locations. */
- X if (current->danger_seen_decay != 0)
- X (current->danger_seen_decay)--;
- X
- X /* We don't check terra incognita for debugging. */
- X if (current->time_last_seen == 0)
- X continue;
- X
- X /* While we're at it, make sure that everything
- X got reset. */
- X if (current->visited != 0)
- X debug ("visited true after BFS");
- X if (current->in_to_do_queue != 0)
- X debug ("in_to_do_queue true after BFS");
- X if (current->successors != 0)
- X debug ("successors != 0 after BFS");
- X }
- X }
- X
- X#ifdef DEBUG_FILE
- X fprintf (debugFile,"\n");
- X fflush (debugFile);
- X#endif DEBUG_FILE
- X}
- X
- X/* Send a character to the server. */
- Xstatic void
- Xsend_char(ch)
- Xunsigned char ch;
- X{
- X /* Send the character. */
- X (void) write (Socket, &ch, 1);
- X}
- X
- X/* Hi, world! Your ass is grass. */
- Xvoid
- Xdo_robot()
- X{
- X /* Debugging shit. */
- X#ifdef DEBUG_FILE
- X debugFile = fopen ("./debug_file","w");
- X#endif DEBUG_FILE
- X
- X /* Clear the maze out, reset all our private variables. */
- X /* {
- X Heh, heh, heh... with this commented out, we remember between
- X deaths!
- X
- X int i, j;
- X
- X robot_time = 1;
- X for (i = 0; i <= HEIGHT; i++)
- X for (j = 0; j <= WIDTH; j++)
- X maze[i][j].time_last_seen = 0;
- X } */
- X
- X /* Find our starting location. */
- X robot_x = robot_y = 0;
- X robot_face = -1;
- X
- X /* Go get 'em! */
- X if (!setjmp (robot_jbuf))
- X {
- X /* Keep doing this until we get longjmp'd. */
- X while (1)
- X {
- X int dest_dir = -1; /* Which way we're going. */
- X int dest_distance = 0; /* How far we have to go. */
- X int i; /* A direction we might go. */
- X int must_escape = 0; /* Nonzero is we must escape. */
- X char our_cmd; /* What we decide to do. */
- X
- X /* Let the screen update. */
- X update_info();
- X
- X /* Wait a bit. */
- X usleep (150000);
- X
- X /* We don't suspect enemies where we're standing. */
- X maze[robot_y][robot_x].enemy_seen_decay = 0;
- X
- X /* We don't know what to do yet. */
- X our_cmd = '\0';
- X
- X /* If there's an enemy within killing distance, go get
- X him. */
- X for (i = north; i <= west; i++)
- X {
- X int enemy_distance;
- X
- X /* Find out how far away he is. */
- X enemy_distance = active_enemies[i].distance;
- X
- X /* If ever there's an enemy with zero walls
- X between us, and his direction is dangerous,
- X then we must escape. */
- X if (active_enemies[i].walls == 0
- X && maze[robot_y + dir_to_ym[i]][robot_x + dir_to_xm[i]]
- X .danger_seen_decay != 0)
- X {
- X must_escape = 1;
- X }
- X
- X /* Find the closest active enemy. */
- X if (enemy_distance != 0 && (dest_distance == 0
- X || enemy_distance < dest_distance))
- X {
- X dest_dir = i;
- X dest_distance = enemy_distance;
- X }
- X }
- X
- X /* If we must escape, do so. */
- X if (must_escape)
- X {
- X int i;
- X /* A direction we could go. */
- X int safe_dir;
- X /* The direction we're going. */
- X bfs_node_ptr safe_node;
- X /* Why we're going there. */
- X
- X /* Find a not-dangerous direction to go in. */
- X safe_dir = -1;
- X safe_node = NULL;
- X for (i = north; i <= west; i++)
- X {
- X int look_x, look_y;
- X bfs_node_ptr current_look;
- X /* Where and why we're looking. */
- X
- X /* Look in a direction. */
- X look_x = robot_x + dir_to_xm[i];
- X look_y = robot_y + dir_to_ym[i];
- X current_look = &(maze[look_y][look_x]);
- X
- X /* If it's not possible to go there, don't. */
- X if (is_a_wall (screen[look_y][look_x])
- X || current_look->time_last_seen == 0)
- X continue;
- X
- X /* If it's not safe to go in that direction,
- X don't. */
- X if (current_look->danger_seen_decay != 0)
- X continue;
- X
- X /* It's safe to go that way. Out of all the
- X safe ways, is it the best? */
- X if (safe_node == NULL
- X || node_compare (safe_node, current_look) == 1)
- X {
- X safe_dir = i;
- X safe_node = current_look;
- X }
- X }
- X
- X /* If we have a safe direction to go in, move there
- X without turning. */
- X if (safe_dir != -1)
- X our_cmd = move[safe_dir];
- X }
- X
- X /* If we have an enemy, charge! */
- X if (our_cmd == '\0' && dest_dir != -1 && !must_escape)
- X {
- X /* Kill! Kill! Kill! */
- X
- X /* If we have to turn to face him, do that. */
- X if (robot_face != dest_dir)
- X our_cmd = turn[dest_dir];
- X
- X /* If our gun can't fire, or if we're right up
- X against our active enemy, then move towards
- X him. */
- X else if (robot_stats.gun == 0 || robot_stats.ammo == 0)
- X our_cmd = move[dest_dir];
- X
- X /* If we have lots of ammo, throw bigger stuff. */
- X else if (robot_stats.ammo > 40
- X && active_enemies[dest_dir].distance > 5)
- X our_cmd = 'F';
- X else if (robot_stats.ammo > 20
- X && active_enemies[dest_dir].distance > 3)
- X our_cmd = 'g';
- X
- X /* Fire! */
- X else
- X our_cmd = 'f';
- X }
- X
- X /* Examine the results of the BFS, see what the best
- X way to go is. */
- X if (our_cmd == '\0')
- X {
- X int i;
- X /* The direction we're thinking about. */
- X bfs_node_ptr current_node;
- X /* What we're thinking about. */
- X int best_dir = -1;
- X /* The direction we're going. */
- X bfs_node_ptr best_node = NULL;
- X /* The reason we're going there. */
- X
- X /* Find the best direction. */
- X for (i = north; i <= west; i++)
- X {
- X int current_x, current_y;
- X
- X /* Get info on this direction. */
- X current_x = robot_x + dir_to_xm[i];
- X current_y = robot_y + dir_to_ym[i];
- X current_node = &(maze[current_y][current_x]);
- X
- X /* If this is the best so far, remember it. */
- X if (!is_a_wall (screen[current_y][current_x])
- X && (best_node == NULL
- X || node_compare (best_node, current_node) == 1))
- X {
- X best_node = current_node;
- X best_dir = i;
- X }
- X }
- X
- X /* Go that direction. */
- X if (best_dir == -1)
- X {
- X /* No direction to go. Turn around. */
- X best_dir = turn_around (robot_face);
- X }
- X#ifdef DEBUG_FILE
- X else
- X {
- X fprintf (debugFile, "Best direction is ");
- X switch (best_dir)
- X {
- X case north:
- X fprintf (debugFile, "north\n");
- X break;
- X case east:
- X fprintf (debugFile, "east\n");
- X break;
- X case south:
- X fprintf (debugFile, "south\n");
- X break;
- X case west:
- X fprintf (debugFile, "west\n");
- X break;
- X default:
- X debug ("Switch blah!");
- X }
- X fprintf (debugFile, "Enemies seen: %d\n",
- X best_node->enemies_seen);
- X fprintf (debugFile, "Enemies suspected: %d\n",
- X best_node->enemies_suspected);
- X fprintf (debugFile, "Mines seen: %d\n",
- X best_node->mines_seen);
- X fprintf (debugFile, "Lowest time: %ld\n",
- X best_node->lowest_time_last_seen);
- X fprintf (debugFile, "Path length: %d\n",
- X best_node->distance_to_target);
- X }
- X fprintf (debugFile, "\n");
- X fflush (debugFile);
- X#endif DEBUG_FILE
- X
- X /* Make our move. */
- X
- X /* If there's no best move, turn around. */
- X if (best_node == NULL)
- X our_cmd = turn[turn_around(robot_face)];
- X
- X /* If there are no enemies/suspected enemies in
- X the best path, and we're not cloaked, and we're
- X not scanning, and we have at least 5 charges,
- X then scan. */
- X /* else if (best_node->enemies_seen == 0
- X && best_node->enemies_suspected == 0
- X && robot_stats.cloak == 0
- X && robot_stats.scan == 0
- X && robot_stats.ammo >= 5)
- X our_cmd = 's'; */
- X
- X /* Otherwise, turn & move in the best direction. */
- X else if (robot_face != best_dir && !must_escape)
- X our_cmd = turn[best_dir];
- X else our_cmd = move[best_dir];
- X }
- X
- X /* Do what's best. */
- X send_char (our_cmd);
- X }
- X }
- X
- X /* This gets called by longjmp(). */
- X else
- X {
- X /* We've been told to quit. */
- X return;
- X }
- X}
- X
- X# endif ROBOT
- END_OF_FILE
- if test 42868 -ne `wc -c <'robot.c'`; then
- echo shar: \"'robot.c'\" unpacked with wrong size!
- fi
- # end of 'robot.c'
- fi
- echo shar: End of archive 1 \(of 4\).
- cp /dev/null ark1isdone
- MISSING=""
- for I in 1 2 3 4 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 4 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-