diff options
Diffstat (limited to 'hunt/hunt/otto.c')
| -rw-r--r-- | hunt/hunt/otto.c | 585 |
1 files changed, 585 insertions, 0 deletions
diff --git a/hunt/hunt/otto.c b/hunt/hunt/otto.c new file mode 100644 index 00000000..ab3b9029 --- /dev/null +++ b/hunt/hunt/otto.c @@ -0,0 +1,585 @@ +# ifdef OTTO +/* + * otto - a hunt otto-matic player + * + * This guy is buggy, unfair, stupid, and not extensible. + * Future versions of hunt will have a subroutine library for + * automatic players to link to. If you write your own "otto" + * please let us know what subroutines you would expect in the + * subroutine library. + * + * $Id: otto.c,v 1.1.1.1 1997/10/04 09:00:14 mrg Exp $ + */ + +# include <curses.h> +# include <ctype.h> +# include "hunt.h" +# include <sys/time.h> +# include <signal.h> +# undef WALL +# undef NORTH +# undef SOUTH +# undef WEST +# undef EAST +# undef FRONT +# undef LEFT +# undef BACK +# undef RIGHT + +# ifdef HPUX +# define random rand +# endif + +# ifndef USE_CURSES +extern char screen[SCREEN_HEIGHT][SCREEN_WIDTH2]; +# define SCREEN(y, x) screen[y][x] +# else +# if defined(BSD_RELEASE) && BSD_RELEASE >= 44 +# define SCREEN(y, x) stdscr->lines[y]->line[x].ch +# else +# define SCREEN(y, x) stdscr->_y[y][x] +# endif +# endif + +# ifndef DEBUG +# define STATIC static +# else +# define STATIC +# endif + +# define OPPONENT "{}i!" +# define PROPONENT "^v<>" +# define WALL "+\\/#*-|" +# define PUSHOVER " bg;*#&" +# define SHOTS "$@Oo:" + +/* number of "directions" */ +# define NUMDIRECTIONS 4 + +/* absolute directions (facings) - counterclockwise */ +# define NORTH 0 +# define WEST 1 +# define SOUTH 2 +# define EAST 3 +# define ALLDIRS 0xf + +/* relative directions - counterclockwise */ +# define FRONT 0 +# define LEFT 1 +# define BACK 2 +# define RIGHT 3 + +# define ABSCHARS "NWSE" +# define RELCHARS "FLBR" +# define DIRKEYS "khjl" + +STATIC char command[BUFSIZ]; +STATIC int comlen; + +# ifdef DEBUG +STATIC FILE *debug = NULL; +# endif + +# define DEADEND 0x1 +# define ON_LEFT 0x2 +# define ON_RIGHT 0x4 +# define ON_SIDE (ON_LEFT|ON_RIGHT) +# define BEEN 0x8 +# define BEEN_SAME 0x10 + +struct item { + char what; + int distance; + int flags; +}; + +STATIC struct item flbr[NUMDIRECTIONS]; + +# define fitem flbr[FRONT] +# define litem flbr[LEFT] +# define bitem flbr[BACK] +# define ritem flbr[RIGHT] + +STATIC int facing; +STATIC int row, col; +STATIC int num_turns; /* for wandering */ +STATIC char been_there[HEIGHT][WIDTH2]; +STATIC struct itimerval pause_time = { { 0, 0 }, { 0, 55000 }}; + +STATIC int stop_look(); +STATIC int look_around(); +STATIC int face_and_move_direction(); +STATIC int attack(); +STATIC int duck(); +STATIC int go_for_ammo(); +STATIC int wander(); + +STATIC SIGNAL_TYPE +nothing() +{ +} + +otto(y, x, face) + int y, x; + char face; +{ + register int i; + extern int Otto_count; + int old_mask; + +# ifdef DEBUG + if (debug == NULL) { + debug = fopen("bug", "w"); + setbuf(debug, NULL); + } + fprintf(debug, "\n%c(%d,%d)", face, y, x); +# endif + (void) signal(SIGALRM, nothing); + old_mask = sigblock(sigmask(SIGALRM)); + setitimer(ITIMER_REAL, &pause_time, NULL); + sigpause(old_mask); + sigsetmask(old_mask); + + /* save away parameters so other functions may use/update info */ + switch (face) { + case '^': facing = NORTH; break; + case '<': facing = WEST; break; + case 'v': facing = SOUTH; break; + case '>': facing = EAST; break; + default: abort(); + } + row = y; col = x; + been_there[row][col] |= 1 << facing; + + /* initially no commands to be sent */ + comlen = 0; + + /* find something to do */ + look_around(); + for (i = 0; i < NUMDIRECTIONS; i++) { + if (strchr(OPPONENT, flbr[i].what) != NULL) { + attack(i, &flbr[i]); + memset(been_there, 0, sizeof been_there); + goto done; + } + } + + if (strchr(SHOTS, bitem.what) != NULL && !(bitem.what & ON_SIDE)) { + duck(BACK); + memset(been_there, 0, sizeof been_there); +# ifdef BOOTS + } else if (go_for_ammo(BOOT_PAIR)) { + memset(been_there, 0, sizeof been_there); + } else if (go_for_ammo(BOOT)) { + memset(been_there, 0, sizeof been_there); +# endif + } else if (go_for_ammo(GMINE)) + memset(been_there, 0, sizeof been_there); + else if (go_for_ammo(MINE)) + memset(been_there, 0, sizeof been_there); + else + wander(); + +done: + (void) write(Socket, command, comlen); + Otto_count += comlen; +# ifdef DEBUG + (void) fwrite(command, 1, comlen, debug); +# endif +} + +# define direction(abs,rel) (((abs) + (rel)) % NUMDIRECTIONS) + +STATIC +stop_look(itemp, c, dist, side) + struct item *itemp; + char c; + int dist; + int side; +{ + switch (c) { + + case SPACE: + if (side) + itemp->flags &= ~DEADEND; + return 0; + + case MINE: + case GMINE: +# ifdef BOOTS + case BOOT: + case BOOT_PAIR: +# endif + if (itemp->distance == -1) { + itemp->distance = dist; + itemp->what = c; + if (side < 0) + itemp->flags |= ON_LEFT; + else if (side > 0) + itemp->flags |= ON_RIGHT; + } + return 0; + + case SHOT: + case GRENADE: + case SATCHEL: + case BOMB: +# ifdef OOZE + case SLIME: +# endif + if (itemp->distance == -1 || (!side + && (itemp->flags & ON_SIDE + || itemp->what == GMINE || itemp->what == MINE))) { + itemp->distance = dist; + itemp->what = c; + itemp->flags &= ~ON_SIDE; + if (side < 0) + itemp->flags |= ON_LEFT; + else if (side > 0) + itemp->flags |= ON_RIGHT; + } + return 0; + + case '{': + case '}': + case 'i': + case '!': + itemp->distance = dist; + itemp->what = c; + itemp->flags &= ~(ON_SIDE|DEADEND); + if (side < 0) + itemp->flags |= ON_LEFT; + else if (side > 0) + itemp->flags |= ON_RIGHT; + return 1; + + default: + /* a wall or unknown object */ + if (side) + return 0; + if (itemp->distance == -1) { + itemp->distance = dist; + itemp->what = c; + } + return 1; + } +} + +look(rel_dir, itemp) + int rel_dir; + struct item *itemp; +{ + register int r, c; + register char ch; + + itemp->what = 0; + itemp->distance = -1; + itemp->flags = DEADEND|BEEN; /* true until proven false */ + + switch (direction(facing, rel_dir)) { + + case NORTH: + if (been_there[row - 1][col] & NORTH) + itemp->flags |= BEEN_SAME; + for (r = row - 1; r >= 0; r--) + for (c = col - 1; c < col + 2; c++) { + ch = SCREEN(r, c); + if (stop_look(itemp, ch, row - r, c - col)) + goto cont_north; + if (c == col && !been_there[r][c]) + itemp->flags &= ~BEEN; + } + cont_north: + if (itemp->flags & DEADEND) { + itemp->flags |= BEEN; + been_there[r][col] |= NORTH; + for (r = row - 1; r > row - itemp->distance; r--) + been_there[r][col] = ALLDIRS; + } + break; + + case SOUTH: + if (been_there[row + 1][col] & SOUTH) + itemp->flags |= BEEN_SAME; + for (r = row + 1; r < HEIGHT; r++) + for (c = col - 1; c < col + 2; c++) { + ch = SCREEN(r, c); + if (stop_look(itemp, ch, r - row, col - c)) + goto cont_south; + if (c == col && !been_there[r][c]) + itemp->flags &= ~BEEN; + } + cont_south: + if (itemp->flags & DEADEND) { + itemp->flags |= BEEN; + been_there[r][col] |= SOUTH; + for (r = row + 1; r < row + itemp->distance; r++) + been_there[r][col] = ALLDIRS; + } + break; + + case WEST: + if (been_there[row][col - 1] & WEST) + itemp->flags |= BEEN_SAME; + for (c = col - 1; c >= 0; c--) + for (r = row - 1; r < row + 2; r++) { + ch = SCREEN(r, c); + if (stop_look(itemp, ch, col - c, row - r)) + goto cont_east; + if (r == row && !been_there[r][c]) + itemp->flags &= ~BEEN; + } + cont_west: + if (itemp->flags & DEADEND) { + itemp->flags |= BEEN; + been_there[r][col] |= WEST; + for (c = col - 1; c > col - itemp->distance; c--) + been_there[row][c] = ALLDIRS; + } + break; + + case EAST: + if (been_there[row][col + 1] & EAST) + itemp->flags |= BEEN_SAME; + for (c = col + 1; c < WIDTH; c++) + for (r = row - 1; r < row + 2; r++) { + ch = SCREEN(r, c); + if (stop_look(itemp, ch, c - col, r - row)) + goto cont_east; + if (r == row && !been_there[r][c]) + itemp->flags &= ~BEEN; + } + cont_east: + if (itemp->flags & DEADEND) { + itemp->flags |= BEEN; + been_there[r][col] |= EAST; + for (c = col + 1; c < col + itemp->distance; c++) + been_there[row][c] = ALLDIRS; + } + break; + + default: + abort(); + } +} + +STATIC +look_around() +{ + register int i; + + for (i = 0; i < NUMDIRECTIONS; i++) { + look(i, &flbr[i]); +# ifdef DEBUG + fprintf(debug, " look(%c)=%c(%d)(0x%x)", + RELCHARS[i], flbr[i].what, flbr[i].distance, flbr[i].flags); +# endif + } +} + +/* + * as a side effect modifies facing and location (row, col) + */ + +STATIC +face_and_move_direction(rel_dir, distance) + int rel_dir, distance; +{ + register int old_facing; + register char cmd; + + old_facing = facing; + cmd = DIRKEYS[facing = direction(facing, rel_dir)]; + + if (rel_dir != FRONT) { + register int i; + struct item items[NUMDIRECTIONS]; + + command[comlen++] = toupper(cmd); + if (distance == 0) { + /* rotate look's to be in right position */ + for (i = 0; i < NUMDIRECTIONS; i++) + items[i] = + flbr[(i + old_facing) % NUMDIRECTIONS]; + memcpy(flbr, items, sizeof flbr); + } + } + while (distance--) { + command[comlen++] = cmd; + switch (facing) { + + case NORTH: row--; break; + case WEST: col--; break; + case SOUTH: row++; break; + case EAST: col++; break; + } + if (distance == 0) + look_around(); + } +} + +STATIC +attack(rel_dir, itemp) + int rel_dir; + struct item *itemp; +{ + if (!(itemp->flags & ON_SIDE)) { + face_and_move_direction(rel_dir, 0); + command[comlen++] = 'o'; + command[comlen++] = 'o'; + duck(FRONT); + command[comlen++] = ' '; + } else if (itemp->distance > 1) { + face_and_move_direction(rel_dir, 2); + duck(FRONT); + } else { + face_and_move_direction(rel_dir, 1); + if (itemp->flags & ON_LEFT) + rel_dir = LEFT; + else + rel_dir = RIGHT; + (void) face_and_move_direction(rel_dir, 0); + command[comlen++] = 'f'; + command[comlen++] = 'f'; + duck(FRONT); + command[comlen++] = ' '; + } +} + +STATIC +duck(rel_dir) + int rel_dir; +{ + int dir; + + switch (dir = direction(facing, rel_dir)) { + + case NORTH: + case SOUTH: + if (strchr(PUSHOVER, SCREEN(row, col - 1)) != NULL) + command[comlen++] = 'h'; + else if (strchr(PUSHOVER, SCREEN(row, col + 1)) != NULL) + command[comlen++] = 'l'; + else if (dir == NORTH + && strchr(PUSHOVER, SCREEN(row + 1, col)) != NULL) + command[comlen++] = 'j'; + else if (dir == SOUTH + && strchr(PUSHOVER, SCREEN(row - 1, col)) != NULL) + command[comlen++] = 'k'; + else if (dir == NORTH) + command[comlen++] = 'k'; + else + command[comlen++] = 'j'; + break; + + case WEST: + case EAST: + if (strchr(PUSHOVER, SCREEN(row - 1, col)) != NULL) + command[comlen++] = 'k'; + else if (strchr(PUSHOVER, SCREEN(row + 1, col)) != NULL) + command[comlen++] = 'j'; + else if (dir == WEST + && strchr(PUSHOVER, SCREEN(row, col + 1)) != NULL) + command[comlen++] = 'l'; + else if (dir == EAST + && strchr(PUSHOVER, SCREEN(row, col - 1)) != NULL) + command[comlen++] = 'h'; + else if (dir == WEST) + command[comlen++] = 'h'; + else + command[comlen++] = 'l'; + break; + } +} + +/* + * go for the closest mine if possible + */ + +STATIC +go_for_ammo(mine) + char mine; +{ + register int i, rel_dir, dist; + + rel_dir = -1; + dist = WIDTH; + for (i = 0; i < NUMDIRECTIONS; i++) { + if (flbr[i].what == mine && flbr[i].distance < dist) { + rel_dir = i; + dist = flbr[i].distance; + } + } + if (rel_dir == -1) + return FALSE; + + if (!(flbr[rel_dir].flags & ON_SIDE) + || flbr[rel_dir].distance > 1) { + if (dist > 4) + dist = 4; + face_and_move_direction(rel_dir, dist); + } else + return FALSE; /* until it's done right */ + return TRUE; +} + +STATIC +wander() +{ + register int i, j, rel_dir, dir_mask, dir_count; + + for (i = 0; i < NUMDIRECTIONS; i++) + if (!(flbr[i].flags & BEEN) || flbr[i].distance <= 1) + break; + if (i == NUMDIRECTIONS) + memset(been_there, 0, sizeof been_there); + dir_mask = dir_count = 0; + for (i = 0; i < NUMDIRECTIONS; i++) { + j = (RIGHT + i) % NUMDIRECTIONS; + if (flbr[j].distance <= 1 || flbr[j].flags & DEADEND) + continue; + if (!(flbr[j].flags & BEEN_SAME)) { + dir_mask = 1 << j; + dir_count = 1; + break; + } + if (j == FRONT + && num_turns > 4 + (random() % + ((flbr[FRONT].flags & BEEN) ? 7 : HEIGHT))) + continue; + dir_mask |= 1 << j; +# ifdef notdef + dir_count++; +# else + dir_count = 1; + break; +# endif + } + if (dir_count == 0) { + duck(random() % NUMDIRECTIONS); + num_turns = 0; + return; + } else if (dir_count == 1) + rel_dir = ffs(dir_mask) - 1; + else { + rel_dir = ffs(dir_mask) - 1; + dir_mask &= ~(1 << rel_dir); + while (dir_mask != 0) { + i = ffs(dir_mask) - 1; + if (random() % 5 == 0) + rel_dir = i; + dir_mask &= ~(1 << i); + } + } + if (rel_dir == FRONT) + num_turns++; + else + num_turns = 0; + +# ifdef DEBUG + fprintf(debug, " w(%c)", RELCHARS[rel_dir]); +# endif + face_and_move_direction(rel_dir, 1); +} + +# endif /* OTTO */ |
