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 * + Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * + 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 * + 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 $
33 * $DragonFly: src/games/hunt/hunt/otto.c,v 1.1 2008/09/02 21:50:20 dillon Exp $
37 * otto - a hunt otto-matic player
39 * This guy is buggy, unfair, stupid, and not extensible.
40 * Future versions of hunt will have a subroutine library for
41 * automatic players to link to. If you write your own "otto"
42 * please let us know what subroutines you would expect in the
57 #define panic(m) _panic(__FILE__,__LINE__,m)
59 useconds_t Otto_pause = 55000;
73 # define SCREEN(y, x) display_atyx(y, x)
75 # define OPPONENT "{}i!"
76 # define PROPONENT "^v<>"
77 # define WALL "+\\/#*-|"
78 # define PUSHOVER " bg;*#&"
79 # define SHOTS "$@Oo:"
81 /* number of "directions" */
82 # define NUMDIRECTIONS 4
83 # define direction(abs,rel) (((abs) + (rel)) % NUMDIRECTIONS)
85 /* absolute directions (facings) - counterclockwise */
92 /* relative directions - counterclockwise */
98 # define ABSCHARS "NWSE"
99 # define RELCHARS "FLBR"
100 # define DIRKEYS "khjl"
102 static char command[1024]; /* XXX */
107 # define ON_RIGHT 0x4
108 # define ON_SIDE (ON_LEFT|ON_RIGHT)
110 # define BEEN_SAME 0x10
118 static struct item flbr[NUMDIRECTIONS];
120 # define fitem flbr[FRONT]
121 # define litem flbr[LEFT]
122 # define bitem flbr[BACK]
123 # define ritem flbr[RIGHT]
127 static int num_turns; /* for wandering */
128 static char been_there[HEIGHT][WIDTH2];
130 static void attack(int, struct item *);
131 static void duck(int);
132 static void face_and_move_direction(int, int);
133 static int go_for_ammo(char);
134 static void ottolook(int, struct item *);
135 static void look_around(void);
136 static int stop_look(struct item *, char, int, int);
137 static void wander(void);
138 static void _panic(const char *, int, const char *);
141 otto(y, x, face, buf, buflen)
149 if (usleep(Otto_pause) < 0)
152 /* save away parameters so other functions may use/update info */
154 case '^': facing = NORTH; break;
155 case '<': facing = WEST; break;
156 case 'v': facing = SOUTH; break;
157 case '>': facing = EAST; break;
158 default: panic("unknown face");
161 been_there[row][col] |= 1 << facing;
163 /* initially no commands to be sent */
166 /* find something to do */
168 for (i = 0; i < NUMDIRECTIONS; i++) {
169 if (strchr(OPPONENT, flbr[i].what) != NULL) {
171 memset(been_there, 0, sizeof been_there);
176 if (strchr(SHOTS, bitem.what) != NULL && !(bitem.what & ON_SIDE)) {
178 memset(been_there, 0, sizeof been_there);
179 } else if (go_for_ammo(BOOT_PAIR)) {
180 memset(been_there, 0, sizeof been_there);
181 } else if (go_for_ammo(BOOT)) {
182 memset(been_there, 0, sizeof been_there);
183 } else if (go_for_ammo(GMINE))
184 memset(been_there, 0, sizeof been_there);
185 else if (go_for_ammo(MINE))
186 memset(been_there, 0, sizeof been_there);
192 if (comlen > (int)buflen)
193 panic("not enough buffer space");
194 memcpy(buf, command, comlen);
200 stop_look(itemp, c, dist, side)
210 itemp->flags &= ~DEADEND;
217 if (itemp->distance == -1) {
218 itemp->distance = dist;
221 itemp->flags |= ON_LEFT;
223 itemp->flags |= ON_RIGHT;
232 if (itemp->distance == -1 || (!side
233 && (itemp->flags & ON_SIDE
234 || itemp->what == GMINE || itemp->what == MINE))) {
235 itemp->distance = dist;
237 itemp->flags &= ~ON_SIDE;
239 itemp->flags |= ON_LEFT;
241 itemp->flags |= ON_RIGHT;
249 itemp->distance = dist;
251 itemp->flags &= ~(ON_SIDE|DEADEND);
253 itemp->flags |= ON_LEFT;
255 itemp->flags |= ON_RIGHT;
259 /* a wall or unknown object */
262 if (itemp->distance == -1) {
263 itemp->distance = dist;
271 ottolook(rel_dir, itemp)
280 itemp->distance = -1;
281 itemp->flags = DEADEND|BEEN; /* true until proven false */
283 switch (direction(facing, rel_dir)) {
286 if (been_there[row - 1][col] & NORTH)
287 itemp->flags |= BEEN_SAME;
288 for (r = row - 1; r >= 0; r--)
289 for (c = col - 1; c < col + 2; c++) {
291 if (stop_look(itemp, ch, row - r, c - col))
293 if (c == col && !been_there[r][c])
294 itemp->flags &= ~BEEN;
297 if (itemp->flags & DEADEND) {
298 itemp->flags |= BEEN;
300 been_there[r][col] |= NORTH;
301 for (r = row - 1; r > row - itemp->distance; r--)
302 been_there[r][col] = ALLDIRS;
307 if (been_there[row + 1][col] & SOUTH)
308 itemp->flags |= BEEN_SAME;
309 for (r = row + 1; r < HEIGHT; r++)
310 for (c = col - 1; c < col + 2; c++) {
312 if (stop_look(itemp, ch, r - row, col - c))
314 if (c == col && !been_there[r][c])
315 itemp->flags &= ~BEEN;
318 if (itemp->flags & DEADEND) {
319 itemp->flags |= BEEN;
321 been_there[r][col] |= SOUTH;
322 for (r = row + 1; r < row + itemp->distance; r++)
323 been_there[r][col] = ALLDIRS;
328 if (been_there[row][col - 1] & WEST)
329 itemp->flags |= BEEN_SAME;
330 for (c = col - 1; c >= 0; c--)
331 for (r = row - 1; r < row + 2; r++) {
333 if (stop_look(itemp, ch, col - c, row - r))
335 if (r == row && !been_there[r][c])
336 itemp->flags &= ~BEEN;
339 if (itemp->flags & DEADEND) {
340 itemp->flags |= BEEN;
341 been_there[r][col] |= WEST;
342 for (c = col - 1; c > col - itemp->distance; c--)
343 been_there[row][c] = ALLDIRS;
348 if (been_there[row][col + 1] & EAST)
349 itemp->flags |= BEEN_SAME;
350 for (c = col + 1; c < WIDTH; c++)
351 for (r = row - 1; r < row + 2; r++) {
353 if (stop_look(itemp, ch, c - col, r - row))
355 if (r == row && !been_there[r][c])
356 itemp->flags &= ~BEEN;
359 if (itemp->flags & DEADEND) {
360 itemp->flags |= BEEN;
361 been_there[r][col] |= EAST;
362 for (c = col + 1; c < col + itemp->distance; c++)
363 been_there[row][c] = ALLDIRS;
368 panic("unknown look");
377 for (i = 0; i < NUMDIRECTIONS; i++) {
378 ottolook(i, &flbr[i]);
383 * as a side effect modifies facing and location (row, col)
387 face_and_move_direction(rel_dir, distance)
388 int rel_dir, distance;
394 cmd = DIRKEYS[facing = direction(facing, rel_dir)];
396 if (rel_dir != FRONT) {
398 struct item items[NUMDIRECTIONS];
400 command[comlen++] = toupper(cmd);
402 /* rotate ottolook's to be in right position */
403 for (i = 0; i < NUMDIRECTIONS; i++)
405 flbr[(i + old_facing) % NUMDIRECTIONS];
406 memcpy(flbr, items, sizeof flbr);
410 command[comlen++] = cmd;
413 case NORTH: row--; break;
414 case WEST: col--; break;
415 case SOUTH: row++; break;
416 case EAST: col++; break;
424 attack(rel_dir, itemp)
428 if (!(itemp->flags & ON_SIDE)) {
429 face_and_move_direction(rel_dir, 0);
430 command[comlen++] = 'o';
431 command[comlen++] = 'o';
433 command[comlen++] = ' ';
434 } else if (itemp->distance > 1) {
435 face_and_move_direction(rel_dir, 2);
438 face_and_move_direction(rel_dir, 1);
439 if (itemp->flags & ON_LEFT)
443 (void) face_and_move_direction(rel_dir, 0);
444 command[comlen++] = 'f';
445 command[comlen++] = 'f';
447 command[comlen++] = ' ';
457 switch (dir = direction(facing, rel_dir)) {
461 if (strchr(PUSHOVER, SCREEN(row, col - 1)) != NULL)
462 command[comlen++] = 'h';
463 else if (strchr(PUSHOVER, SCREEN(row, col + 1)) != NULL)
464 command[comlen++] = 'l';
465 else if (dir == NORTH
466 && strchr(PUSHOVER, SCREEN(row + 1, col)) != NULL)
467 command[comlen++] = 'j';
468 else if (dir == SOUTH
469 && strchr(PUSHOVER, SCREEN(row - 1, col)) != NULL)
470 command[comlen++] = 'k';
471 else if (dir == NORTH)
472 command[comlen++] = 'k';
474 command[comlen++] = 'j';
479 if (strchr(PUSHOVER, SCREEN(row - 1, col)) != NULL)
480 command[comlen++] = 'k';
481 else if (strchr(PUSHOVER, SCREEN(row + 1, col)) != NULL)
482 command[comlen++] = 'j';
484 && strchr(PUSHOVER, SCREEN(row, col + 1)) != NULL)
485 command[comlen++] = 'l';
487 && strchr(PUSHOVER, SCREEN(row, col - 1)) != NULL)
488 command[comlen++] = 'h';
489 else if (dir == WEST)
490 command[comlen++] = 'h';
492 command[comlen++] = 'l';
498 * go for the closest mine if possible
505 int i, rel_dir, dist;
509 for (i = 0; i < NUMDIRECTIONS; i++) {
510 if (flbr[i].what == mine && flbr[i].distance < dist) {
512 dist = flbr[i].distance;
518 if (!(flbr[rel_dir].flags & ON_SIDE)
519 || flbr[rel_dir].distance > 1) {
522 face_and_move_direction(rel_dir, dist);
524 return FALSE; /* until it's done right */
531 int i, j, rel_dir, dir_mask, dir_count;
533 for (i = 0; i < NUMDIRECTIONS; i++)
534 if (!(flbr[i].flags & BEEN) || flbr[i].distance <= 1)
536 if (i == NUMDIRECTIONS)
537 memset(been_there, 0, sizeof been_there);
538 dir_mask = dir_count = 0;
539 for (i = 0; i < NUMDIRECTIONS; i++) {
540 j = (RIGHT + i) % NUMDIRECTIONS;
541 if (flbr[j].distance <= 1 || flbr[j].flags & DEADEND)
543 if (!(flbr[j].flags & BEEN_SAME)) {
549 && num_turns > 4 + (random() %
550 ((flbr[FRONT].flags & BEEN) ? 7 : HEIGHT)))
556 if (dir_count == 0) {
557 duck(random() % NUMDIRECTIONS);
561 rel_dir = ffs(dir_mask) - 1;
563 if (rel_dir == FRONT)
568 face_and_move_direction(rel_dir, 1);
571 /* Otto always re-enters the game, cloaked. */
573 otto_quit(int old_status __unused)
579 _panic(file, line, msg)
585 fprintf(stderr, "%s:%d: panic! %s\n", file, line, msg);