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 $
33 * $DragonFly: src/games/hunt/hunt/otto.c,v 1.2 2008/09/04 16:12:51 swildner 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(int y
, int x
, char face
, char *buf
, size_t buflen
)
145 if (usleep(Otto_pause
) < 0)
148 /* save away parameters so other functions may use/update info */
150 case '^': facing
= NORTH
; break;
151 case '<': facing
= WEST
; break;
152 case 'v': facing
= SOUTH
; break;
153 case '>': facing
= EAST
; break;
154 default: panic("unknown face");
157 been_there
[row
][col
] |= 1 << facing
;
159 /* initially no commands to be sent */
162 /* find something to do */
164 for (i
= 0; i
< NUMDIRECTIONS
; i
++) {
165 if (strchr(OPPONENT
, flbr
[i
].what
) != NULL
) {
167 memset(been_there
, 0, sizeof been_there
);
172 if (strchr(SHOTS
, bitem
.what
) != NULL
&& !(bitem
.what
& ON_SIDE
)) {
174 memset(been_there
, 0, sizeof been_there
);
175 } else if (go_for_ammo(BOOT_PAIR
)) {
176 memset(been_there
, 0, sizeof been_there
);
177 } else if (go_for_ammo(BOOT
)) {
178 memset(been_there
, 0, sizeof been_there
);
179 } else if (go_for_ammo(GMINE
))
180 memset(been_there
, 0, sizeof been_there
);
181 else if (go_for_ammo(MINE
))
182 memset(been_there
, 0, sizeof been_there
);
188 if (comlen
> (int)buflen
)
189 panic("not enough buffer space");
190 memcpy(buf
, command
, comlen
);
196 stop_look(struct item
*itemp
, char c
, int dist
, int side
)
202 itemp
->flags
&= ~DEADEND
;
209 if (itemp
->distance
== -1) {
210 itemp
->distance
= dist
;
213 itemp
->flags
|= ON_LEFT
;
215 itemp
->flags
|= ON_RIGHT
;
224 if (itemp
->distance
== -1 || (!side
225 && (itemp
->flags
& ON_SIDE
226 || itemp
->what
== GMINE
|| itemp
->what
== MINE
))) {
227 itemp
->distance
= dist
;
229 itemp
->flags
&= ~ON_SIDE
;
231 itemp
->flags
|= ON_LEFT
;
233 itemp
->flags
|= ON_RIGHT
;
241 itemp
->distance
= dist
;
243 itemp
->flags
&= ~(ON_SIDE
|DEADEND
);
245 itemp
->flags
|= ON_LEFT
;
247 itemp
->flags
|= ON_RIGHT
;
251 /* a wall or unknown object */
254 if (itemp
->distance
== -1) {
255 itemp
->distance
= dist
;
263 ottolook(int rel_dir
, struct item
*itemp
)
270 itemp
->distance
= -1;
271 itemp
->flags
= DEADEND
|BEEN
; /* true until proven false */
273 switch (direction(facing
, rel_dir
)) {
276 if (been_there
[row
- 1][col
] & NORTH
)
277 itemp
->flags
|= BEEN_SAME
;
278 for (r
= row
- 1; r
>= 0; r
--)
279 for (c
= col
- 1; c
< col
+ 2; c
++) {
281 if (stop_look(itemp
, ch
, row
- r
, c
- col
))
283 if (c
== col
&& !been_there
[r
][c
])
284 itemp
->flags
&= ~BEEN
;
287 if (itemp
->flags
& DEADEND
) {
288 itemp
->flags
|= BEEN
;
290 been_there
[r
][col
] |= NORTH
;
291 for (r
= row
- 1; r
> row
- itemp
->distance
; r
--)
292 been_there
[r
][col
] = ALLDIRS
;
297 if (been_there
[row
+ 1][col
] & SOUTH
)
298 itemp
->flags
|= BEEN_SAME
;
299 for (r
= row
+ 1; r
< HEIGHT
; r
++)
300 for (c
= col
- 1; c
< col
+ 2; c
++) {
302 if (stop_look(itemp
, ch
, r
- row
, col
- c
))
304 if (c
== col
&& !been_there
[r
][c
])
305 itemp
->flags
&= ~BEEN
;
308 if (itemp
->flags
& DEADEND
) {
309 itemp
->flags
|= BEEN
;
311 been_there
[r
][col
] |= SOUTH
;
312 for (r
= row
+ 1; r
< row
+ itemp
->distance
; r
++)
313 been_there
[r
][col
] = ALLDIRS
;
318 if (been_there
[row
][col
- 1] & WEST
)
319 itemp
->flags
|= BEEN_SAME
;
320 for (c
= col
- 1; c
>= 0; c
--)
321 for (r
= row
- 1; r
< row
+ 2; r
++) {
323 if (stop_look(itemp
, ch
, col
- c
, row
- r
))
325 if (r
== row
&& !been_there
[r
][c
])
326 itemp
->flags
&= ~BEEN
;
329 if (itemp
->flags
& DEADEND
) {
330 itemp
->flags
|= BEEN
;
331 been_there
[r
][col
] |= WEST
;
332 for (c
= col
- 1; c
> col
- itemp
->distance
; c
--)
333 been_there
[row
][c
] = ALLDIRS
;
338 if (been_there
[row
][col
+ 1] & EAST
)
339 itemp
->flags
|= BEEN_SAME
;
340 for (c
= col
+ 1; c
< WIDTH
; c
++)
341 for (r
= row
- 1; r
< row
+ 2; r
++) {
343 if (stop_look(itemp
, ch
, c
- col
, r
- row
))
345 if (r
== row
&& !been_there
[r
][c
])
346 itemp
->flags
&= ~BEEN
;
349 if (itemp
->flags
& DEADEND
) {
350 itemp
->flags
|= BEEN
;
351 been_there
[r
][col
] |= EAST
;
352 for (c
= col
+ 1; c
< col
+ itemp
->distance
; c
++)
353 been_there
[row
][c
] = ALLDIRS
;
358 panic("unknown look");
367 for (i
= 0; i
< NUMDIRECTIONS
; i
++) {
368 ottolook(i
, &flbr
[i
]);
373 * as a side effect modifies facing and location (row, col)
377 face_and_move_direction(int rel_dir
, int distance
)
383 cmd
= DIRKEYS
[facing
= direction(facing
, rel_dir
)];
385 if (rel_dir
!= FRONT
) {
387 struct item items
[NUMDIRECTIONS
];
389 command
[comlen
++] = toupper(cmd
);
391 /* rotate ottolook's to be in right position */
392 for (i
= 0; i
< NUMDIRECTIONS
; i
++)
394 flbr
[(i
+ old_facing
) % NUMDIRECTIONS
];
395 memcpy(flbr
, items
, sizeof flbr
);
399 command
[comlen
++] = cmd
;
402 case NORTH
: row
--; break;
403 case WEST
: col
--; break;
404 case SOUTH
: row
++; break;
405 case EAST
: col
++; break;
413 attack(int rel_dir
, struct item
*itemp
)
415 if (!(itemp
->flags
& ON_SIDE
)) {
416 face_and_move_direction(rel_dir
, 0);
417 command
[comlen
++] = 'o';
418 command
[comlen
++] = 'o';
420 command
[comlen
++] = ' ';
421 } else if (itemp
->distance
> 1) {
422 face_and_move_direction(rel_dir
, 2);
425 face_and_move_direction(rel_dir
, 1);
426 if (itemp
->flags
& ON_LEFT
)
430 (void) face_and_move_direction(rel_dir
, 0);
431 command
[comlen
++] = 'f';
432 command
[comlen
++] = 'f';
434 command
[comlen
++] = ' ';
443 switch (dir
= direction(facing
, rel_dir
)) {
447 if (strchr(PUSHOVER
, SCREEN(row
, col
- 1)) != NULL
)
448 command
[comlen
++] = 'h';
449 else if (strchr(PUSHOVER
, SCREEN(row
, col
+ 1)) != NULL
)
450 command
[comlen
++] = 'l';
451 else if (dir
== NORTH
452 && strchr(PUSHOVER
, SCREEN(row
+ 1, col
)) != NULL
)
453 command
[comlen
++] = 'j';
454 else if (dir
== SOUTH
455 && strchr(PUSHOVER
, SCREEN(row
- 1, col
)) != NULL
)
456 command
[comlen
++] = 'k';
457 else if (dir
== NORTH
)
458 command
[comlen
++] = 'k';
460 command
[comlen
++] = 'j';
465 if (strchr(PUSHOVER
, SCREEN(row
- 1, col
)) != NULL
)
466 command
[comlen
++] = 'k';
467 else if (strchr(PUSHOVER
, SCREEN(row
+ 1, col
)) != NULL
)
468 command
[comlen
++] = 'j';
470 && strchr(PUSHOVER
, SCREEN(row
, col
+ 1)) != NULL
)
471 command
[comlen
++] = 'l';
473 && strchr(PUSHOVER
, SCREEN(row
, col
- 1)) != NULL
)
474 command
[comlen
++] = 'h';
475 else if (dir
== WEST
)
476 command
[comlen
++] = 'h';
478 command
[comlen
++] = 'l';
484 * go for the closest mine if possible
488 go_for_ammo(char mine
)
490 int i
, rel_dir
, dist
;
494 for (i
= 0; i
< NUMDIRECTIONS
; i
++) {
495 if (flbr
[i
].what
== mine
&& flbr
[i
].distance
< dist
) {
497 dist
= flbr
[i
].distance
;
503 if (!(flbr
[rel_dir
].flags
& ON_SIDE
)
504 || flbr
[rel_dir
].distance
> 1) {
507 face_and_move_direction(rel_dir
, dist
);
509 return FALSE
; /* until it's done right */
516 int i
, j
, rel_dir
, dir_mask
, dir_count
;
518 for (i
= 0; i
< NUMDIRECTIONS
; i
++)
519 if (!(flbr
[i
].flags
& BEEN
) || flbr
[i
].distance
<= 1)
521 if (i
== NUMDIRECTIONS
)
522 memset(been_there
, 0, sizeof been_there
);
523 dir_mask
= dir_count
= 0;
524 for (i
= 0; i
< NUMDIRECTIONS
; i
++) {
525 j
= (RIGHT
+ i
) % NUMDIRECTIONS
;
526 if (flbr
[j
].distance
<= 1 || flbr
[j
].flags
& DEADEND
)
528 if (!(flbr
[j
].flags
& BEEN_SAME
)) {
534 && num_turns
> 4 + (random() %
535 ((flbr
[FRONT
].flags
& BEEN
) ? 7 : HEIGHT
)))
541 if (dir_count
== 0) {
542 duck(random() % NUMDIRECTIONS
);
546 rel_dir
= ffs(dir_mask
) - 1;
548 if (rel_dir
== FRONT
)
553 face_and_move_direction(rel_dir
, 1);
556 /* Otto always re-enters the game, cloaked. */
558 otto_quit(int old_status __unused
)
564 _panic(const char *file
, int line
, const char *msg
)
567 fprintf(stderr
, "%s:%d: panic! %s\n", file
, line
, msg
);