1 /* $NetBSD: otto.c,v 1.3 1999/04/18 03:29:01 simonb Exp $ */
4 * otto - a hunt otto-matic player
6 * This guy is buggy, unfair, stupid, and not extensible.
7 * Future versions of hunt will have a subroutine library for
8 * automatic players to link to. If you write your own "otto"
9 * please let us know what subroutines you would expect in the
13 #include <sys/cdefs.h>
15 __RCSID("$NetBSD: otto.c,v 1.3 1999/04/18 03:29:01 simonb Exp $");
18 # include <sys/time.h>
41 extern char screen
[SCREEN_HEIGHT
][SCREEN_WIDTH2
];
42 # define SCREEN(y, x) screen[y][x]
44 # define SCREEN(y, x) mvinch(y, x)
48 # define STATIC static
53 # define OPPONENT "{}i!"
54 # define PROPONENT "^v<>"
55 # define WALL "+\\/#*-|"
56 # define PUSHOVER " bg;*#&"
57 # define SHOTS "$@Oo:"
59 /* number of "directions" */
60 # define NUMDIRECTIONS 4
62 /* absolute directions (facings) - counterclockwise */
69 /* relative directions - counterclockwise */
75 # define ABSCHARS "NWSE"
76 # define RELCHARS "FLBR"
77 # define DIRKEYS "khjl"
79 STATIC
char command
[BUFSIZ
];
83 STATIC
FILE *debug
= NULL
;
89 # define ON_SIDE (ON_LEFT|ON_RIGHT)
91 # define BEEN_SAME 0x10
99 STATIC
struct item flbr
[NUMDIRECTIONS
];
101 # define fitem flbr[FRONT]
102 # define litem flbr[LEFT]
103 # define bitem flbr[BACK]
104 # define ritem flbr[RIGHT]
108 STATIC
int num_turns
; /* for wandering */
109 STATIC
char been_there
[HEIGHT
][WIDTH2
];
110 STATIC
struct itimerval pause_time
= { { 0, 0 }, { 0, 55000 }};
112 STATIC
void attack
__P((int, struct item
*));
113 STATIC
void duck
__P((int));
114 STATIC
void face_and_move_direction
__P((int, int));
115 STATIC
int go_for_ammo
__P((char));
116 STATIC
void ottolook
__P((int, struct item
*));
117 STATIC
void look_around
__P((void));
118 STATIC SIGNAL_TYPE nothing
__P((int));
119 STATIC
int stop_look
__P((struct item
*, char, int, int));
120 STATIC
void wander
__P((void));
134 extern int Otto_count
;
139 debug
= fopen("bug", "w");
142 fprintf(debug
, "\n%c(%d,%d)", face
, y
, x
);
144 (void) signal(SIGALRM
, nothing
);
145 old_mask
= sigblock(sigmask(SIGALRM
));
146 setitimer(ITIMER_REAL
, &pause_time
, NULL
);
148 sigsetmask(old_mask
);
150 /* save away parameters so other functions may use/update info */
152 case '^': facing
= NORTH
; break;
153 case '<': facing
= WEST
; break;
154 case 'v': facing
= SOUTH
; break;
155 case '>': facing
= EAST
; break;
159 been_there
[row
][col
] |= 1 << facing
;
161 /* initially no commands to be sent */
164 /* find something to do */
166 for (i
= 0; i
< NUMDIRECTIONS
; i
++) {
167 if (strchr(OPPONENT
, flbr
[i
].what
) != NULL
) {
169 memset(been_there
, 0, sizeof been_there
);
174 if (strchr(SHOTS
, bitem
.what
) != NULL
&& !(bitem
.what
& ON_SIDE
)) {
176 memset(been_there
, 0, sizeof been_there
);
178 } else if (go_for_ammo(BOOT_PAIR
)) {
179 memset(been_there
, 0, sizeof been_there
);
180 } else if (go_for_ammo(BOOT
)) {
181 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
);
191 (void) write(Socket
, command
, comlen
);
192 Otto_count
+= comlen
;
194 (void) fwrite(command
, 1, comlen
, debug
);
198 # define direction(abs,rel) (((abs) + (rel)) % NUMDIRECTIONS)
201 stop_look(itemp
, c
, dist
, side
)
211 itemp
->flags
&= ~DEADEND
;
220 if (itemp
->distance
== -1) {
221 itemp
->distance
= dist
;
224 itemp
->flags
|= ON_LEFT
;
226 itemp
->flags
|= ON_RIGHT
;
237 if (itemp
->distance
== -1 || (!side
238 && (itemp
->flags
& ON_SIDE
239 || itemp
->what
== GMINE
|| itemp
->what
== MINE
))) {
240 itemp
->distance
= dist
;
242 itemp
->flags
&= ~ON_SIDE
;
244 itemp
->flags
|= ON_LEFT
;
246 itemp
->flags
|= ON_RIGHT
;
254 itemp
->distance
= dist
;
256 itemp
->flags
&= ~(ON_SIDE
|DEADEND
);
258 itemp
->flags
|= ON_LEFT
;
260 itemp
->flags
|= ON_RIGHT
;
264 /* a wall or unknown object */
267 if (itemp
->distance
== -1) {
268 itemp
->distance
= dist
;
276 ottolook(rel_dir
, itemp
)
285 itemp
->distance
= -1;
286 itemp
->flags
= DEADEND
|BEEN
; /* true until proven false */
288 switch (direction(facing
, rel_dir
)) {
291 if (been_there
[row
- 1][col
] & NORTH
)
292 itemp
->flags
|= BEEN_SAME
;
293 for (r
= row
- 1; r
>= 0; r
--)
294 for (c
= col
- 1; c
< col
+ 2; c
++) {
296 if (stop_look(itemp
, ch
, row
- r
, c
- col
))
298 if (c
== col
&& !been_there
[r
][c
])
299 itemp
->flags
&= ~BEEN
;
302 if (itemp
->flags
& DEADEND
) {
303 itemp
->flags
|= BEEN
;
304 been_there
[r
][col
] |= NORTH
;
305 for (r
= row
- 1; r
> row
- itemp
->distance
; r
--)
306 been_there
[r
][col
] = ALLDIRS
;
311 if (been_there
[row
+ 1][col
] & SOUTH
)
312 itemp
->flags
|= BEEN_SAME
;
313 for (r
= row
+ 1; r
< HEIGHT
; r
++)
314 for (c
= col
- 1; c
< col
+ 2; c
++) {
316 if (stop_look(itemp
, ch
, r
- row
, col
- c
))
318 if (c
== col
&& !been_there
[r
][c
])
319 itemp
->flags
&= ~BEEN
;
322 if (itemp
->flags
& DEADEND
) {
323 itemp
->flags
|= BEEN
;
324 been_there
[r
][col
] |= SOUTH
;
325 for (r
= row
+ 1; r
< row
+ itemp
->distance
; r
++)
326 been_there
[r
][col
] = ALLDIRS
;
331 if (been_there
[row
][col
- 1] & WEST
)
332 itemp
->flags
|= BEEN_SAME
;
333 for (c
= col
- 1; c
>= 0; c
--)
334 for (r
= row
- 1; r
< row
+ 2; r
++) {
336 if (stop_look(itemp
, ch
, col
- c
, row
- r
))
338 if (r
== row
&& !been_there
[r
][c
])
339 itemp
->flags
&= ~BEEN
;
342 if (itemp
->flags
& DEADEND
) {
343 itemp
->flags
|= BEEN
;
344 been_there
[r
][col
] |= WEST
;
345 for (c
= col
- 1; c
> col
- itemp
->distance
; c
--)
346 been_there
[row
][c
] = ALLDIRS
;
351 if (been_there
[row
][col
+ 1] & EAST
)
352 itemp
->flags
|= BEEN_SAME
;
353 for (c
= col
+ 1; c
< WIDTH
; c
++)
354 for (r
= row
- 1; r
< row
+ 2; r
++) {
356 if (stop_look(itemp
, ch
, c
- col
, r
- row
))
358 if (r
== row
&& !been_there
[r
][c
])
359 itemp
->flags
&= ~BEEN
;
362 if (itemp
->flags
& DEADEND
) {
363 itemp
->flags
|= BEEN
;
364 been_there
[r
][col
] |= EAST
;
365 for (c
= col
+ 1; c
< col
+ itemp
->distance
; c
++)
366 been_there
[row
][c
] = ALLDIRS
;
380 for (i
= 0; i
< NUMDIRECTIONS
; i
++) {
381 ottolook(i
, &flbr
[i
]);
383 fprintf(debug
, " ottolook(%c)=%c(%d)(0x%x)",
384 RELCHARS
[i
], flbr
[i
].what
, flbr
[i
].distance
, flbr
[i
].flags
);
390 * as a side effect modifies facing and location (row, col)
394 face_and_move_direction(rel_dir
, distance
)
395 int rel_dir
, distance
;
401 cmd
= DIRKEYS
[facing
= direction(facing
, rel_dir
)];
403 if (rel_dir
!= FRONT
) {
405 struct item items
[NUMDIRECTIONS
];
407 command
[comlen
++] = toupper(cmd
);
409 /* rotate ottolook's to be in right position */
410 for (i
= 0; i
< NUMDIRECTIONS
; i
++)
412 flbr
[(i
+ old_facing
) % NUMDIRECTIONS
];
413 memcpy(flbr
, items
, sizeof flbr
);
417 command
[comlen
++] = cmd
;
420 case NORTH
: row
--; break;
421 case WEST
: col
--; break;
422 case SOUTH
: row
++; break;
423 case EAST
: col
++; break;
431 attack(rel_dir
, itemp
)
435 if (!(itemp
->flags
& ON_SIDE
)) {
436 face_and_move_direction(rel_dir
, 0);
437 command
[comlen
++] = 'o';
438 command
[comlen
++] = 'o';
440 command
[comlen
++] = ' ';
441 } else if (itemp
->distance
> 1) {
442 face_and_move_direction(rel_dir
, 2);
445 face_and_move_direction(rel_dir
, 1);
446 if (itemp
->flags
& ON_LEFT
)
450 (void) face_and_move_direction(rel_dir
, 0);
451 command
[comlen
++] = 'f';
452 command
[comlen
++] = 'f';
454 command
[comlen
++] = ' ';
464 switch (dir
= direction(facing
, rel_dir
)) {
468 if (strchr(PUSHOVER
, SCREEN(row
, col
- 1)) != NULL
)
469 command
[comlen
++] = 'h';
470 else if (strchr(PUSHOVER
, SCREEN(row
, col
+ 1)) != NULL
)
471 command
[comlen
++] = 'l';
472 else if (dir
== NORTH
473 && strchr(PUSHOVER
, SCREEN(row
+ 1, col
)) != NULL
)
474 command
[comlen
++] = 'j';
475 else if (dir
== SOUTH
476 && strchr(PUSHOVER
, SCREEN(row
- 1, col
)) != NULL
)
477 command
[comlen
++] = 'k';
478 else if (dir
== NORTH
)
479 command
[comlen
++] = 'k';
481 command
[comlen
++] = 'j';
486 if (strchr(PUSHOVER
, SCREEN(row
- 1, col
)) != NULL
)
487 command
[comlen
++] = 'k';
488 else if (strchr(PUSHOVER
, SCREEN(row
+ 1, col
)) != NULL
)
489 command
[comlen
++] = 'j';
491 && strchr(PUSHOVER
, SCREEN(row
, col
+ 1)) != NULL
)
492 command
[comlen
++] = 'l';
494 && strchr(PUSHOVER
, SCREEN(row
, col
- 1)) != NULL
)
495 command
[comlen
++] = 'h';
496 else if (dir
== WEST
)
497 command
[comlen
++] = 'h';
499 command
[comlen
++] = 'l';
505 * go for the closest mine if possible
512 int i
, rel_dir
, dist
;
516 for (i
= 0; i
< NUMDIRECTIONS
; i
++) {
517 if (flbr
[i
].what
== mine
&& flbr
[i
].distance
< dist
) {
519 dist
= flbr
[i
].distance
;
525 if (!(flbr
[rel_dir
].flags
& ON_SIDE
)
526 || flbr
[rel_dir
].distance
> 1) {
529 face_and_move_direction(rel_dir
, dist
);
531 return FALSE
; /* until it's done right */
538 int i
, j
, rel_dir
, dir_mask
, dir_count
;
540 for (i
= 0; i
< NUMDIRECTIONS
; i
++)
541 if (!(flbr
[i
].flags
& BEEN
) || flbr
[i
].distance
<= 1)
543 if (i
== NUMDIRECTIONS
)
544 memset(been_there
, 0, sizeof been_there
);
545 dir_mask
= dir_count
= 0;
546 for (i
= 0; i
< NUMDIRECTIONS
; i
++) {
547 j
= (RIGHT
+ i
) % NUMDIRECTIONS
;
548 if (flbr
[j
].distance
<= 1 || flbr
[j
].flags
& DEADEND
)
550 if (!(flbr
[j
].flags
& BEEN_SAME
)) {
556 && num_turns
> 4 + (random() %
557 ((flbr
[FRONT
].flags
& BEEN
) ? 7 : HEIGHT
)))
567 if (dir_count
== 0) {
568 duck(random() % NUMDIRECTIONS
);
571 } else if (dir_count
== 1)
572 rel_dir
= ffs(dir_mask
) - 1;
574 rel_dir
= ffs(dir_mask
) - 1;
575 dir_mask
&= ~(1 << rel_dir
);
576 while (dir_mask
!= 0) {
577 i
= ffs(dir_mask
) - 1;
578 if (random() % 5 == 0)
580 dir_mask
&= ~(1 << i
);
583 if (rel_dir
== FRONT
)
589 fprintf(debug
, " w(%c)", RELCHARS
[rel_dir
]);
591 face_and_move_direction(rel_dir
, 1);