]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - hunt/hunt/otto.c
581efaa3442ee765a2f55fe4fa7b9fad9613f68b
[bsdgames-darwin.git] / hunt / hunt / otto.c
1 /* $NetBSD: otto.c,v 1.3 1999/04/18 03:29:01 simonb Exp $ */
2 # ifdef OTTO
3 /*
4 * otto - a hunt otto-matic player
5 *
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
10 * subroutine library.
11 */
12
13 #include <sys/cdefs.h>
14 #ifndef lint
15 __RCSID("$NetBSD: otto.c,v 1.3 1999/04/18 03:29:01 simonb Exp $");
16 #endif /* not lint */
17
18 # include <sys/time.h>
19 # include <curses.h>
20 # include <ctype.h>
21 # include <signal.h>
22 # include <stdlib.h>
23 # include <unistd.h>
24 # include "hunt.h"
25
26 # undef WALL
27 # undef NORTH
28 # undef SOUTH
29 # undef WEST
30 # undef EAST
31 # undef FRONT
32 # undef LEFT
33 # undef BACK
34 # undef RIGHT
35
36 # ifdef HPUX
37 # define random rand
38 # endif
39
40 # ifndef USE_CURSES
41 extern char screen[SCREEN_HEIGHT][SCREEN_WIDTH2];
42 # define SCREEN(y, x) screen[y][x]
43 # else
44 # define SCREEN(y, x) mvinch(y, x)
45 # endif
46
47 # ifndef DEBUG
48 # define STATIC static
49 # else
50 # define STATIC
51 # endif
52
53 # define OPPONENT "{}i!"
54 # define PROPONENT "^v<>"
55 # define WALL "+\\/#*-|"
56 # define PUSHOVER " bg;*#&"
57 # define SHOTS "$@Oo:"
58
59 /* number of "directions" */
60 # define NUMDIRECTIONS 4
61
62 /* absolute directions (facings) - counterclockwise */
63 # define NORTH 0
64 # define WEST 1
65 # define SOUTH 2
66 # define EAST 3
67 # define ALLDIRS 0xf
68
69 /* relative directions - counterclockwise */
70 # define FRONT 0
71 # define LEFT 1
72 # define BACK 2
73 # define RIGHT 3
74
75 # define ABSCHARS "NWSE"
76 # define RELCHARS "FLBR"
77 # define DIRKEYS "khjl"
78
79 STATIC char command[BUFSIZ];
80 STATIC int comlen;
81
82 # ifdef DEBUG
83 STATIC FILE *debug = NULL;
84 # endif
85
86 # define DEADEND 0x1
87 # define ON_LEFT 0x2
88 # define ON_RIGHT 0x4
89 # define ON_SIDE (ON_LEFT|ON_RIGHT)
90 # define BEEN 0x8
91 # define BEEN_SAME 0x10
92
93 struct item {
94 char what;
95 int distance;
96 int flags;
97 };
98
99 STATIC struct item flbr[NUMDIRECTIONS];
100
101 # define fitem flbr[FRONT]
102 # define litem flbr[LEFT]
103 # define bitem flbr[BACK]
104 # define ritem flbr[RIGHT]
105
106 STATIC int facing;
107 STATIC int row, col;
108 STATIC int num_turns; /* for wandering */
109 STATIC char been_there[HEIGHT][WIDTH2];
110 STATIC struct itimerval pause_time = { { 0, 0 }, { 0, 55000 }};
111
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));
121
122 STATIC SIGNAL_TYPE
123 nothing(dummy)
124 int dummy;
125 {
126 }
127
128 void
129 otto(y, x, face)
130 int y, x;
131 char face;
132 {
133 int i;
134 extern int Otto_count;
135 int old_mask;
136
137 # ifdef DEBUG
138 if (debug == NULL) {
139 debug = fopen("bug", "w");
140 setbuf(debug, NULL);
141 }
142 fprintf(debug, "\n%c(%d,%d)", face, y, x);
143 # endif
144 (void) signal(SIGALRM, nothing);
145 old_mask = sigblock(sigmask(SIGALRM));
146 setitimer(ITIMER_REAL, &pause_time, NULL);
147 sigpause(old_mask);
148 sigsetmask(old_mask);
149
150 /* save away parameters so other functions may use/update info */
151 switch (face) {
152 case '^': facing = NORTH; break;
153 case '<': facing = WEST; break;
154 case 'v': facing = SOUTH; break;
155 case '>': facing = EAST; break;
156 default: abort();
157 }
158 row = y; col = x;
159 been_there[row][col] |= 1 << facing;
160
161 /* initially no commands to be sent */
162 comlen = 0;
163
164 /* find something to do */
165 look_around();
166 for (i = 0; i < NUMDIRECTIONS; i++) {
167 if (strchr(OPPONENT, flbr[i].what) != NULL) {
168 attack(i, &flbr[i]);
169 memset(been_there, 0, sizeof been_there);
170 goto done;
171 }
172 }
173
174 if (strchr(SHOTS, bitem.what) != NULL && !(bitem.what & ON_SIDE)) {
175 duck(BACK);
176 memset(been_there, 0, sizeof been_there);
177 # ifdef BOOTS
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);
182 # endif
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);
187 else
188 wander();
189
190 done:
191 (void) write(Socket, command, comlen);
192 Otto_count += comlen;
193 # ifdef DEBUG
194 (void) fwrite(command, 1, comlen, debug);
195 # endif
196 }
197
198 # define direction(abs,rel) (((abs) + (rel)) % NUMDIRECTIONS)
199
200 STATIC int
201 stop_look(itemp, c, dist, side)
202 struct item *itemp;
203 char c;
204 int dist;
205 int side;
206 {
207 switch (c) {
208
209 case SPACE:
210 if (side)
211 itemp->flags &= ~DEADEND;
212 return 0;
213
214 case MINE:
215 case GMINE:
216 # ifdef BOOTS
217 case BOOT:
218 case BOOT_PAIR:
219 # endif
220 if (itemp->distance == -1) {
221 itemp->distance = dist;
222 itemp->what = c;
223 if (side < 0)
224 itemp->flags |= ON_LEFT;
225 else if (side > 0)
226 itemp->flags |= ON_RIGHT;
227 }
228 return 0;
229
230 case SHOT:
231 case GRENADE:
232 case SATCHEL:
233 case BOMB:
234 # ifdef OOZE
235 case SLIME:
236 # endif
237 if (itemp->distance == -1 || (!side
238 && (itemp->flags & ON_SIDE
239 || itemp->what == GMINE || itemp->what == MINE))) {
240 itemp->distance = dist;
241 itemp->what = c;
242 itemp->flags &= ~ON_SIDE;
243 if (side < 0)
244 itemp->flags |= ON_LEFT;
245 else if (side > 0)
246 itemp->flags |= ON_RIGHT;
247 }
248 return 0;
249
250 case '{':
251 case '}':
252 case 'i':
253 case '!':
254 itemp->distance = dist;
255 itemp->what = c;
256 itemp->flags &= ~(ON_SIDE|DEADEND);
257 if (side < 0)
258 itemp->flags |= ON_LEFT;
259 else if (side > 0)
260 itemp->flags |= ON_RIGHT;
261 return 1;
262
263 default:
264 /* a wall or unknown object */
265 if (side)
266 return 0;
267 if (itemp->distance == -1) {
268 itemp->distance = dist;
269 itemp->what = c;
270 }
271 return 1;
272 }
273 }
274
275 STATIC void
276 ottolook(rel_dir, itemp)
277 int rel_dir;
278 struct item *itemp;
279 {
280 int r, c;
281 char ch;
282
283 r = 0;
284 itemp->what = 0;
285 itemp->distance = -1;
286 itemp->flags = DEADEND|BEEN; /* true until proven false */
287
288 switch (direction(facing, rel_dir)) {
289
290 case NORTH:
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++) {
295 ch = SCREEN(r, c);
296 if (stop_look(itemp, ch, row - r, c - col))
297 goto cont_north;
298 if (c == col && !been_there[r][c])
299 itemp->flags &= ~BEEN;
300 }
301 cont_north:
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;
307 }
308 break;
309
310 case SOUTH:
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++) {
315 ch = SCREEN(r, c);
316 if (stop_look(itemp, ch, r - row, col - c))
317 goto cont_south;
318 if (c == col && !been_there[r][c])
319 itemp->flags &= ~BEEN;
320 }
321 cont_south:
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;
327 }
328 break;
329
330 case WEST:
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++) {
335 ch = SCREEN(r, c);
336 if (stop_look(itemp, ch, col - c, row - r))
337 goto cont_west;
338 if (r == row && !been_there[r][c])
339 itemp->flags &= ~BEEN;
340 }
341 cont_west:
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;
347 }
348 break;
349
350 case EAST:
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++) {
355 ch = SCREEN(r, c);
356 if (stop_look(itemp, ch, c - col, r - row))
357 goto cont_east;
358 if (r == row && !been_there[r][c])
359 itemp->flags &= ~BEEN;
360 }
361 cont_east:
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;
367 }
368 break;
369
370 default:
371 abort();
372 }
373 }
374
375 STATIC void
376 look_around()
377 {
378 int i;
379
380 for (i = 0; i < NUMDIRECTIONS; i++) {
381 ottolook(i, &flbr[i]);
382 # ifdef DEBUG
383 fprintf(debug, " ottolook(%c)=%c(%d)(0x%x)",
384 RELCHARS[i], flbr[i].what, flbr[i].distance, flbr[i].flags);
385 # endif
386 }
387 }
388
389 /*
390 * as a side effect modifies facing and location (row, col)
391 */
392
393 STATIC void
394 face_and_move_direction(rel_dir, distance)
395 int rel_dir, distance;
396 {
397 int old_facing;
398 char cmd;
399
400 old_facing = facing;
401 cmd = DIRKEYS[facing = direction(facing, rel_dir)];
402
403 if (rel_dir != FRONT) {
404 int i;
405 struct item items[NUMDIRECTIONS];
406
407 command[comlen++] = toupper(cmd);
408 if (distance == 0) {
409 /* rotate ottolook's to be in right position */
410 for (i = 0; i < NUMDIRECTIONS; i++)
411 items[i] =
412 flbr[(i + old_facing) % NUMDIRECTIONS];
413 memcpy(flbr, items, sizeof flbr);
414 }
415 }
416 while (distance--) {
417 command[comlen++] = cmd;
418 switch (facing) {
419
420 case NORTH: row--; break;
421 case WEST: col--; break;
422 case SOUTH: row++; break;
423 case EAST: col++; break;
424 }
425 if (distance == 0)
426 look_around();
427 }
428 }
429
430 STATIC void
431 attack(rel_dir, itemp)
432 int rel_dir;
433 struct item *itemp;
434 {
435 if (!(itemp->flags & ON_SIDE)) {
436 face_and_move_direction(rel_dir, 0);
437 command[comlen++] = 'o';
438 command[comlen++] = 'o';
439 duck(FRONT);
440 command[comlen++] = ' ';
441 } else if (itemp->distance > 1) {
442 face_and_move_direction(rel_dir, 2);
443 duck(FRONT);
444 } else {
445 face_and_move_direction(rel_dir, 1);
446 if (itemp->flags & ON_LEFT)
447 rel_dir = LEFT;
448 else
449 rel_dir = RIGHT;
450 (void) face_and_move_direction(rel_dir, 0);
451 command[comlen++] = 'f';
452 command[comlen++] = 'f';
453 duck(FRONT);
454 command[comlen++] = ' ';
455 }
456 }
457
458 STATIC void
459 duck(rel_dir)
460 int rel_dir;
461 {
462 int dir;
463
464 switch (dir = direction(facing, rel_dir)) {
465
466 case NORTH:
467 case SOUTH:
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';
480 else
481 command[comlen++] = 'j';
482 break;
483
484 case WEST:
485 case EAST:
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';
490 else if (dir == WEST
491 && strchr(PUSHOVER, SCREEN(row, col + 1)) != NULL)
492 command[comlen++] = 'l';
493 else if (dir == EAST
494 && strchr(PUSHOVER, SCREEN(row, col - 1)) != NULL)
495 command[comlen++] = 'h';
496 else if (dir == WEST)
497 command[comlen++] = 'h';
498 else
499 command[comlen++] = 'l';
500 break;
501 }
502 }
503
504 /*
505 * go for the closest mine if possible
506 */
507
508 STATIC int
509 go_for_ammo(mine)
510 char mine;
511 {
512 int i, rel_dir, dist;
513
514 rel_dir = -1;
515 dist = WIDTH;
516 for (i = 0; i < NUMDIRECTIONS; i++) {
517 if (flbr[i].what == mine && flbr[i].distance < dist) {
518 rel_dir = i;
519 dist = flbr[i].distance;
520 }
521 }
522 if (rel_dir == -1)
523 return FALSE;
524
525 if (!(flbr[rel_dir].flags & ON_SIDE)
526 || flbr[rel_dir].distance > 1) {
527 if (dist > 4)
528 dist = 4;
529 face_and_move_direction(rel_dir, dist);
530 } else
531 return FALSE; /* until it's done right */
532 return TRUE;
533 }
534
535 STATIC void
536 wander()
537 {
538 int i, j, rel_dir, dir_mask, dir_count;
539
540 for (i = 0; i < NUMDIRECTIONS; i++)
541 if (!(flbr[i].flags & BEEN) || flbr[i].distance <= 1)
542 break;
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)
549 continue;
550 if (!(flbr[j].flags & BEEN_SAME)) {
551 dir_mask = 1 << j;
552 dir_count = 1;
553 break;
554 }
555 if (j == FRONT
556 && num_turns > 4 + (random() %
557 ((flbr[FRONT].flags & BEEN) ? 7 : HEIGHT)))
558 continue;
559 dir_mask |= 1 << j;
560 # ifdef notdef
561 dir_count++;
562 # else
563 dir_count = 1;
564 break;
565 # endif
566 }
567 if (dir_count == 0) {
568 duck(random() % NUMDIRECTIONS);
569 num_turns = 0;
570 return;
571 } else if (dir_count == 1)
572 rel_dir = ffs(dir_mask) - 1;
573 else {
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)
579 rel_dir = i;
580 dir_mask &= ~(1 << i);
581 }
582 }
583 if (rel_dir == FRONT)
584 num_turns++;
585 else
586 num_turns = 0;
587
588 # ifdef DEBUG
589 fprintf(debug, " w(%c)", RELCHARS[rel_dir]);
590 # endif
591 face_and_move_direction(rel_dir, 1);
592 }
593
594 # endif /* OTTO */