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
);