2 * Copyright (c) 1983-2003, Regents of the University of California.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the University of California, San Francisco nor
15 * the names of its contributors may be used to endorse or promote
16 * products derived from this software without specific prior written
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * $OpenBSD: otto.c,v 1.9 2006/03/27 00:10:15 tedu Exp $
32 * $NetBSD: otto.c,v 1.2 1997/10/10 16:32:39 lukem Exp $
36 * otto - a hunt otto-matic player
38 * This guy is buggy, unfair, stupid, and not extensible.
39 * Future versions of hunt will have a subroutine library for
40 * automatic players to link to. If you write your own "otto"
41 * please let us know what subroutines you would expect in the
56 #define panic(m) _panic(__FILE__,__LINE__,m)
58 useconds_t Otto_pause = 55000;
72 # define SCREEN(y, x) display_atyx(y, x)
74 # define OPPONENT "{}i!"
75 # define PROPONENT "^v<>"
76 # define WALL "+\\/#*-|"
77 # define PUSHOVER " bg;*#&"
78 # define SHOTS "$@Oo:"
80 /* number of "directions" */
81 # define NUMDIRECTIONS 4
82 # define direction(abs,rel) (((abs) + (rel)) % NUMDIRECTIONS)
84 /* absolute directions (facings) - counterclockwise */
91 /* relative directions - counterclockwise */
97 # define ABSCHARS "NWSE"
98 # define RELCHARS "FLBR"
99 # define DIRKEYS "khjl"
101 static char command[1024]; /* XXX */
106 # define ON_RIGHT 0x4
107 # define ON_SIDE (ON_LEFT|ON_RIGHT)
109 # define BEEN_SAME 0x10
117 static struct item flbr[NUMDIRECTIONS];
119 # define fitem flbr[FRONT]
120 # define litem flbr[LEFT]
121 # define bitem flbr[BACK]
122 # define ritem flbr[RIGHT]
126 static int num_turns; /* for wandering */
127 static char been_there[HEIGHT][WIDTH2];
129 static void attack(int, struct item *);
130 static void duck(int);
131 static void face_and_move_direction(int, int);
132 static int go_for_ammo(char);
133 static void ottolook(int, struct item *);
134 static void look_around(void);
135 static int stop_look(struct item *, char, int, int);
136 static void wander(void);
137 static void _panic(const char *, int, const char *);
140 otto(int y, int x, char face, char *buf, size_t buflen)
144 if (usleep(Otto_pause) < 0)
147 /* save away parameters so other functions may use/update info */
149 case '^': facing = NORTH; break;
150 case '<': facing = WEST; break;
151 case 'v': facing = SOUTH; break;
152 case '>': facing = EAST; break;
153 default: panic("unknown face");
156 been_there[row][col] |= 1 << facing;
158 /* initially no commands to be sent */
161 /* find something to do */
163 for (i = 0; i < NUMDIRECTIONS; i++) {
164 if (strchr(OPPONENT, flbr[i].what) != NULL) {
166 memset(been_there, 0, sizeof been_there);
171 if (strchr(SHOTS, bitem.what) != NULL && !(bitem.what & ON_SIDE)) {
173 memset(been_there, 0, sizeof been_there);
174 } else if (go_for_ammo(BOOT_PAIR)) {
175 memset(been_there, 0, sizeof been_there);
176 } else if (go_for_ammo(BOOT)) {
177 memset(been_there, 0, sizeof been_there);
178 } else if (go_for_ammo(GMINE))
179 memset(been_there, 0, sizeof been_there);
180 else if (go_for_ammo(MINE))
181 memset(been_there, 0, sizeof been_there);
187 if (comlen > (int)buflen)
188 panic("not enough buffer space");
189 memcpy(buf, command, comlen);
195 stop_look(struct item *itemp, char c, int dist, int side)
201 itemp->flags &= ~DEADEND;
208 if (itemp->distance == -1) {
209 itemp->distance = dist;
212 itemp->flags |= ON_LEFT;
214 itemp->flags |= ON_RIGHT;
223 if (itemp->distance == -1 || (!side
224 && (itemp->flags & ON_SIDE
225 || itemp->what == GMINE || itemp->what == MINE))) {
226 itemp->distance = dist;
228 itemp->flags &= ~ON_SIDE;
230 itemp->flags |= ON_LEFT;
232 itemp->flags |= ON_RIGHT;
240 itemp->distance = dist;
242 itemp->flags &= ~(ON_SIDE|DEADEND);
244 itemp->flags |= ON_LEFT;
246 itemp->flags |= ON_RIGHT;
250 /* a wall or unknown object */
253 if (itemp->distance == -1) {
254 itemp->distance = dist;
262 ottolook(int rel_dir, struct item *itemp)
269 itemp->distance = -1;
270 itemp->flags = DEADEND|BEEN; /* true until proven false */
272 switch (direction(facing, rel_dir)) {
275 if (been_there[row - 1][col] & NORTH)
276 itemp->flags |= BEEN_SAME;
277 for (r = row - 1; r >= 0; r--)
278 for (c = col - 1; c < col + 2; c++) {
280 if (stop_look(itemp, ch, row - r, c - col))
282 if (c == col && !been_there[r][c])
283 itemp->flags &= ~BEEN;
286 if (itemp->flags & DEADEND) {
287 itemp->flags |= BEEN;
289 been_there[r][col] |= NORTH;
290 for (r = row - 1; r > row - itemp->distance; r--)
291 been_there[r][col] = ALLDIRS;
296 if (been_there[row + 1][col] & SOUTH)
297 itemp->flags |= BEEN_SAME;
298 for (r = row + 1; r < HEIGHT; r++)
299 for (c = col - 1; c < col + 2; c++) {
301 if (stop_look(itemp, ch, r - row, col - c))
303 if (c == col && !been_there[r][c])
304 itemp->flags &= ~BEEN;
307 if (itemp->flags & DEADEND) {
308 itemp->flags |= BEEN;
310 been_there[r][col] |= SOUTH;
311 for (r = row + 1; r < row + itemp->distance; r++)
312 been_there[r][col] = ALLDIRS;
317 if (been_there[row][col - 1] & WEST)
318 itemp->flags |= BEEN_SAME;
319 for (c = col - 1; c >= 0; c--)
320 for (r = row - 1; r < row + 2; r++) {
322 if (stop_look(itemp, ch, col - c, row - r))
324 if (r == row && !been_there[r][c])
325 itemp->flags &= ~BEEN;
328 if (itemp->flags & DEADEND) {
329 itemp->flags |= BEEN;
330 been_there[r][col] |= WEST;
331 for (c = col - 1; c > col - itemp->distance; c--)
332 been_there[row][c] = ALLDIRS;
337 if (been_there[row][col + 1] & EAST)
338 itemp->flags |= BEEN_SAME;
339 for (c = col + 1; c < WIDTH; c++)
340 for (r = row - 1; r < row + 2; r++) {
342 if (stop_look(itemp, ch, c - col, r - row))
344 if (r == row && !been_there[r][c])
345 itemp->flags &= ~BEEN;
348 if (itemp->flags & DEADEND) {
349 itemp->flags |= BEEN;
350 been_there[r][col] |= EAST;
351 for (c = col + 1; c < col + itemp->distance; c++)
352 been_there[row][c] = ALLDIRS;
357 panic("unknown look");
366 for (i = 0; i < NUMDIRECTIONS; i++) {
367 ottolook(i, &flbr[i]);
372 * as a side effect modifies facing and location (row, col)
376 face_and_move_direction(int rel_dir, int distance)
382 cmd = DIRKEYS[facing = direction(facing, rel_dir)];
384 if (rel_dir != FRONT) {
386 struct item items[NUMDIRECTIONS];
388 command[comlen++] = toupper(cmd);
390 /* rotate ottolook's to be in right position */
391 for (i = 0; i < NUMDIRECTIONS; i++)
393 flbr[(i + old_facing) % NUMDIRECTIONS];
394 memcpy(flbr, items, sizeof flbr);
398 command[comlen++] = cmd;
401 case NORTH: row--; break;
402 case WEST: col--; break;
403 case SOUTH: row++; break;
404 case EAST: col++; break;
412 attack(int rel_dir, struct item *itemp)
414 if (!(itemp->flags & ON_SIDE)) {
415 face_and_move_direction(rel_dir, 0);
416 command[comlen++] = 'o';
417 command[comlen++] = 'o';
419 command[comlen++] = ' ';
420 } else if (itemp->distance > 1) {
421 face_and_move_direction(rel_dir, 2);
424 face_and_move_direction(rel_dir, 1);
425 if (itemp->flags & ON_LEFT)
429 face_and_move_direction(rel_dir, 0);
430 command[comlen++] = 'f';
431 command[comlen++] = 'f';
433 command[comlen++] = ' ';
442 switch (dir = direction(facing, rel_dir)) {
446 if (strchr(PUSHOVER, SCREEN(row, col - 1)) != NULL)
447 command[comlen++] = 'h';
448 else if (strchr(PUSHOVER, SCREEN(row, col + 1)) != NULL)
449 command[comlen++] = 'l';
450 else if (dir == NORTH
451 && strchr(PUSHOVER, SCREEN(row + 1, col)) != NULL)
452 command[comlen++] = 'j';
453 else if (dir == SOUTH
454 && strchr(PUSHOVER, SCREEN(row - 1, col)) != NULL)
455 command[comlen++] = 'k';
456 else if (dir == NORTH)
457 command[comlen++] = 'k';
459 command[comlen++] = 'j';
464 if (strchr(PUSHOVER, SCREEN(row - 1, col)) != NULL)
465 command[comlen++] = 'k';
466 else if (strchr(PUSHOVER, SCREEN(row + 1, col)) != NULL)
467 command[comlen++] = 'j';
469 && strchr(PUSHOVER, SCREEN(row, col + 1)) != NULL)
470 command[comlen++] = 'l';
472 && strchr(PUSHOVER, SCREEN(row, col - 1)) != NULL)
473 command[comlen++] = 'h';
474 else if (dir == WEST)
475 command[comlen++] = 'h';
477 command[comlen++] = 'l';
483 * go for the closest mine if possible
487 go_for_ammo(char mine)
489 int i, rel_dir, dist;
493 for (i = 0; i < NUMDIRECTIONS; i++) {
494 if (flbr[i].what == mine && flbr[i].distance < dist) {
496 dist = flbr[i].distance;
502 if (!(flbr[rel_dir].flags & ON_SIDE)
503 || flbr[rel_dir].distance > 1) {
506 face_and_move_direction(rel_dir, dist);
508 return FALSE; /* until it's done right */
515 int i, j, rel_dir, dir_mask, dir_count;
517 for (i = 0; i < NUMDIRECTIONS; i++)
518 if (!(flbr[i].flags & BEEN) || flbr[i].distance <= 1)
520 if (i == NUMDIRECTIONS)
521 memset(been_there, 0, sizeof been_there);
522 dir_mask = dir_count = 0;
523 for (i = 0; i < NUMDIRECTIONS; i++) {
524 j = (RIGHT + i) % NUMDIRECTIONS;
525 if (flbr[j].distance <= 1 || flbr[j].flags & DEADEND)
527 if (!(flbr[j].flags & BEEN_SAME)) {
533 && num_turns > 4 + (random() %
534 ((flbr[FRONT].flags & BEEN) ? 7 : HEIGHT)))
540 if (dir_count == 0) {
541 duck(random() % NUMDIRECTIONS);
545 rel_dir = ffs(dir_mask) - 1;
547 if (rel_dir == FRONT)
552 face_and_move_direction(rel_dir, 1);
555 /* Otto always re-enters the game, cloaked. */
557 otto_quit(int old_status __unused)
563 _panic(const char *file, int line, const char *msg)
566 fprintf(stderr, "%s:%d: panic! %s\n", file, line, msg);