]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - hunt/hunt/otto.c
Mark unused parameters, nonreturning functions and format functions in
[bsdgames-darwin.git] / hunt / hunt / otto.c
1 /* $NetBSD: otto.c,v 1.7 2004/02/08 22:23:50 jsm Exp $ */
2 # ifdef OTTO
3 /*
4 * Copyright (c) 1983-2003, Regents of the University of California.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * + Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * + Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * + Neither the name of the University of California, San Francisco nor
17 * the names of its contributors may be used to endorse or promote
18 * products derived from this software without specific prior written
19 * permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * otto - a hunt otto-matic player
36 *
37 * This guy is buggy, unfair, stupid, and not extensible.
38 * Future versions of hunt will have a subroutine library for
39 * automatic players to link to. If you write your own "otto"
40 * please let us know what subroutines you would expect in the
41 * subroutine library.
42 *
43 * Id: otto.c,v 1.14 2003/04/16 06:11:54 gregc Exp
44 */
45
46 #include <sys/cdefs.h>
47 #ifndef lint
48 __RCSID("$NetBSD: otto.c,v 1.7 2004/02/08 22:23:50 jsm Exp $");
49 #endif /* not lint */
50
51 # include <sys/time.h>
52 # include <curses.h>
53 # include <ctype.h>
54 # include <signal.h>
55 # include <stdlib.h>
56 # include <unistd.h>
57 # include "hunt.h"
58
59 # undef WALL
60 # undef NORTH
61 # undef SOUTH
62 # undef WEST
63 # undef EAST
64 # undef FRONT
65 # undef LEFT
66 # undef BACK
67 # undef RIGHT
68
69 # ifdef HPUX
70 # define random rand
71 # endif
72
73 # ifndef USE_CURSES
74 extern char screen[SCREEN_HEIGHT][SCREEN_WIDTH2];
75 # define SCREEN(y, x) screen[y][x]
76 # else
77 # define SCREEN(y, x) mvinch(y, x)
78 # endif
79
80 # ifndef DEBUG
81 # define STATIC static
82 # else
83 # define STATIC
84 # endif
85
86 # define OPPONENT "{}i!"
87 # define PROPONENT "^v<>"
88 # define WALL "+\\/#*-|"
89 # define PUSHOVER " bg;*#&"
90 # define SHOTS "$@Oo:"
91
92 /* number of "directions" */
93 # define NUMDIRECTIONS 4
94
95 /* absolute directions (facings) - counterclockwise */
96 # define NORTH 0
97 # define WEST 1
98 # define SOUTH 2
99 # define EAST 3
100 # define ALLDIRS 0xf
101
102 /* relative directions - counterclockwise */
103 # define FRONT 0
104 # define LEFT 1
105 # define BACK 2
106 # define RIGHT 3
107
108 # define ABSCHARS "NWSE"
109 # define RELCHARS "FLBR"
110 # define DIRKEYS "khjl"
111
112 STATIC char command[BUFSIZ];
113 STATIC int comlen;
114
115 # ifdef DEBUG
116 STATIC FILE *debug = NULL;
117 # endif
118
119 # define DEADEND 0x1
120 # define ON_LEFT 0x2
121 # define ON_RIGHT 0x4
122 # define ON_SIDE (ON_LEFT|ON_RIGHT)
123 # define BEEN 0x8
124 # define BEEN_SAME 0x10
125
126 struct item {
127 char what;
128 int distance;
129 int flags;
130 };
131
132 STATIC struct item flbr[NUMDIRECTIONS];
133
134 # define fitem flbr[FRONT]
135 # define litem flbr[LEFT]
136 # define bitem flbr[BACK]
137 # define ritem flbr[RIGHT]
138
139 STATIC int facing;
140 STATIC int row, col;
141 STATIC int num_turns; /* for wandering */
142 STATIC char been_there[HEIGHT][WIDTH2];
143 STATIC struct itimerval pause_time = { { 0, 0 }, { 0, 55000 }};
144
145 STATIC void attack(int, struct item *);
146 STATIC void duck(int);
147 STATIC void face_and_move_direction(int, int);
148 STATIC int go_for_ammo(char);
149 STATIC void ottolook(int, struct item *);
150 STATIC void look_around(void);
151 STATIC SIGNAL_TYPE nothing(int);
152 STATIC int stop_look(struct item *, char, int, int);
153 STATIC void wander(void);
154
155 extern int Otto_count;
156
157 STATIC SIGNAL_TYPE
158 nothing(dummy)
159 int dummy __attribute__((__unused__));
160 {
161 }
162
163 void
164 otto(y, x, face)
165 int y, x;
166 char face;
167 {
168 int i;
169 int old_mask;
170
171 # ifdef DEBUG
172 if (debug == NULL) {
173 debug = fopen("bug", "w");
174 setbuf(debug, NULL);
175 }
176 fprintf(debug, "\n%c(%d,%d)", face, y, x);
177 # endif
178 (void) signal(SIGALRM, nothing);
179 old_mask = sigblock(sigmask(SIGALRM));
180 setitimer(ITIMER_REAL, &pause_time, NULL);
181 sigpause(old_mask);
182 sigsetmask(old_mask);
183
184 /* save away parameters so other functions may use/update info */
185 switch (face) {
186 case '^': facing = NORTH; break;
187 case '<': facing = WEST; break;
188 case 'v': facing = SOUTH; break;
189 case '>': facing = EAST; break;
190 default: abort();
191 }
192 row = y; col = x;
193 been_there[row][col] |= 1 << facing;
194
195 /* initially no commands to be sent */
196 comlen = 0;
197
198 /* find something to do */
199 look_around();
200 for (i = 0; i < NUMDIRECTIONS; i++) {
201 if (strchr(OPPONENT, flbr[i].what) != NULL) {
202 attack(i, &flbr[i]);
203 memset(been_there, 0, sizeof been_there);
204 goto done;
205 }
206 }
207
208 if (strchr(SHOTS, bitem.what) != NULL && !(bitem.what & ON_SIDE)) {
209 duck(BACK);
210 memset(been_there, 0, sizeof been_there);
211 # ifdef BOOTS
212 } else if (go_for_ammo(BOOT_PAIR)) {
213 memset(been_there, 0, sizeof been_there);
214 } else if (go_for_ammo(BOOT)) {
215 memset(been_there, 0, sizeof been_there);
216 # endif
217 } else if (go_for_ammo(GMINE))
218 memset(been_there, 0, sizeof been_there);
219 else if (go_for_ammo(MINE))
220 memset(been_there, 0, sizeof been_there);
221 else
222 wander();
223
224 done:
225 (void) write(Socket, command, comlen);
226 Otto_count += comlen;
227 # ifdef DEBUG
228 (void) fwrite(command, 1, comlen, debug);
229 # endif
230 }
231
232 # define direction(abs,rel) (((abs) + (rel)) % NUMDIRECTIONS)
233
234 STATIC int
235 stop_look(itemp, c, dist, side)
236 struct item *itemp;
237 char c;
238 int dist;
239 int side;
240 {
241 switch (c) {
242
243 case SPACE:
244 if (side)
245 itemp->flags &= ~DEADEND;
246 return 0;
247
248 case MINE:
249 case GMINE:
250 # ifdef BOOTS
251 case BOOT:
252 case BOOT_PAIR:
253 # endif
254 if (itemp->distance == -1) {
255 itemp->distance = dist;
256 itemp->what = c;
257 if (side < 0)
258 itemp->flags |= ON_LEFT;
259 else if (side > 0)
260 itemp->flags |= ON_RIGHT;
261 }
262 return 0;
263
264 case SHOT:
265 case GRENADE:
266 case SATCHEL:
267 case BOMB:
268 # ifdef OOZE
269 case SLIME:
270 # endif
271 if (itemp->distance == -1 || (!side
272 && (itemp->flags & ON_SIDE
273 || itemp->what == GMINE || itemp->what == MINE))) {
274 itemp->distance = dist;
275 itemp->what = c;
276 itemp->flags &= ~ON_SIDE;
277 if (side < 0)
278 itemp->flags |= ON_LEFT;
279 else if (side > 0)
280 itemp->flags |= ON_RIGHT;
281 }
282 return 0;
283
284 case '{':
285 case '}':
286 case 'i':
287 case '!':
288 itemp->distance = dist;
289 itemp->what = c;
290 itemp->flags &= ~(ON_SIDE|DEADEND);
291 if (side < 0)
292 itemp->flags |= ON_LEFT;
293 else if (side > 0)
294 itemp->flags |= ON_RIGHT;
295 return 1;
296
297 default:
298 /* a wall or unknown object */
299 if (side)
300 return 0;
301 if (itemp->distance == -1) {
302 itemp->distance = dist;
303 itemp->what = c;
304 }
305 return 1;
306 }
307 }
308
309 STATIC void
310 ottolook(rel_dir, itemp)
311 int rel_dir;
312 struct item *itemp;
313 {
314 int r, c;
315 char ch;
316
317 r = 0;
318 itemp->what = 0;
319 itemp->distance = -1;
320 itemp->flags = DEADEND|BEEN; /* true until proven false */
321
322 switch (direction(facing, rel_dir)) {
323
324 case NORTH:
325 if (been_there[row - 1][col] & NORTH)
326 itemp->flags |= BEEN_SAME;
327 for (r = row - 1; r >= 0; r--)
328 for (c = col - 1; c < col + 2; c++) {
329 ch = SCREEN(r, c);
330 if (stop_look(itemp, ch, row - r, c - col))
331 goto cont_north;
332 if (c == col && !been_there[r][c])
333 itemp->flags &= ~BEEN;
334 }
335 cont_north:
336 if (itemp->flags & DEADEND) {
337 itemp->flags |= BEEN;
338 been_there[r][col] |= NORTH;
339 for (r = row - 1; r > row - itemp->distance; r--)
340 been_there[r][col] = ALLDIRS;
341 }
342 break;
343
344 case SOUTH:
345 if (been_there[row + 1][col] & SOUTH)
346 itemp->flags |= BEEN_SAME;
347 for (r = row + 1; r < HEIGHT; r++)
348 for (c = col - 1; c < col + 2; c++) {
349 ch = SCREEN(r, c);
350 if (stop_look(itemp, ch, r - row, col - c))
351 goto cont_south;
352 if (c == col && !been_there[r][c])
353 itemp->flags &= ~BEEN;
354 }
355 cont_south:
356 if (itemp->flags & DEADEND) {
357 itemp->flags |= BEEN;
358 been_there[r][col] |= SOUTH;
359 for (r = row + 1; r < row + itemp->distance; r++)
360 been_there[r][col] = ALLDIRS;
361 }
362 break;
363
364 case WEST:
365 if (been_there[row][col - 1] & WEST)
366 itemp->flags |= BEEN_SAME;
367 for (c = col - 1; c >= 0; c--)
368 for (r = row - 1; r < row + 2; r++) {
369 ch = SCREEN(r, c);
370 if (stop_look(itemp, ch, col - c, row - r))
371 goto cont_west;
372 if (r == row && !been_there[r][c])
373 itemp->flags &= ~BEEN;
374 }
375 cont_west:
376 if (itemp->flags & DEADEND) {
377 itemp->flags |= BEEN;
378 been_there[r][col] |= WEST;
379 for (c = col - 1; c > col - itemp->distance; c--)
380 been_there[row][c] = ALLDIRS;
381 }
382 break;
383
384 case EAST:
385 if (been_there[row][col + 1] & EAST)
386 itemp->flags |= BEEN_SAME;
387 for (c = col + 1; c < WIDTH; c++)
388 for (r = row - 1; r < row + 2; r++) {
389 ch = SCREEN(r, c);
390 if (stop_look(itemp, ch, c - col, r - row))
391 goto cont_east;
392 if (r == row && !been_there[r][c])
393 itemp->flags &= ~BEEN;
394 }
395 cont_east:
396 if (itemp->flags & DEADEND) {
397 itemp->flags |= BEEN;
398 been_there[r][col] |= EAST;
399 for (c = col + 1; c < col + itemp->distance; c++)
400 been_there[row][c] = ALLDIRS;
401 }
402 break;
403
404 default:
405 abort();
406 }
407 }
408
409 STATIC void
410 look_around()
411 {
412 int i;
413
414 for (i = 0; i < NUMDIRECTIONS; i++) {
415 ottolook(i, &flbr[i]);
416 # ifdef DEBUG
417 fprintf(debug, " ottolook(%c)=%c(%d)(0x%x)",
418 RELCHARS[i], flbr[i].what, flbr[i].distance, flbr[i].flags);
419 # endif
420 }
421 }
422
423 /*
424 * as a side effect modifies facing and location (row, col)
425 */
426
427 STATIC void
428 face_and_move_direction(rel_dir, distance)
429 int rel_dir, distance;
430 {
431 int old_facing;
432 char cmd;
433
434 old_facing = facing;
435 cmd = DIRKEYS[facing = direction(facing, rel_dir)];
436
437 if (rel_dir != FRONT) {
438 int i;
439 struct item items[NUMDIRECTIONS];
440
441 command[comlen++] = toupper(cmd);
442 if (distance == 0) {
443 /* rotate ottolook's to be in right position */
444 for (i = 0; i < NUMDIRECTIONS; i++)
445 items[i] =
446 flbr[(i + old_facing) % NUMDIRECTIONS];
447 memcpy(flbr, items, sizeof flbr);
448 }
449 }
450 while (distance--) {
451 command[comlen++] = cmd;
452 switch (facing) {
453
454 case NORTH: row--; break;
455 case WEST: col--; break;
456 case SOUTH: row++; break;
457 case EAST: col++; break;
458 }
459 if (distance == 0)
460 look_around();
461 }
462 }
463
464 STATIC void
465 attack(rel_dir, itemp)
466 int rel_dir;
467 struct item *itemp;
468 {
469 if (!(itemp->flags & ON_SIDE)) {
470 face_and_move_direction(rel_dir, 0);
471 command[comlen++] = 'o';
472 command[comlen++] = 'o';
473 duck(FRONT);
474 command[comlen++] = ' ';
475 } else if (itemp->distance > 1) {
476 face_and_move_direction(rel_dir, 2);
477 duck(FRONT);
478 } else {
479 face_and_move_direction(rel_dir, 1);
480 if (itemp->flags & ON_LEFT)
481 rel_dir = LEFT;
482 else
483 rel_dir = RIGHT;
484 (void) face_and_move_direction(rel_dir, 0);
485 command[comlen++] = 'f';
486 command[comlen++] = 'f';
487 duck(FRONT);
488 command[comlen++] = ' ';
489 }
490 }
491
492 STATIC void
493 duck(rel_dir)
494 int rel_dir;
495 {
496 int dir;
497
498 switch (dir = direction(facing, rel_dir)) {
499
500 case NORTH:
501 case SOUTH:
502 if (strchr(PUSHOVER, SCREEN(row, col - 1)) != NULL)
503 command[comlen++] = 'h';
504 else if (strchr(PUSHOVER, SCREEN(row, col + 1)) != NULL)
505 command[comlen++] = 'l';
506 else if (dir == NORTH
507 && strchr(PUSHOVER, SCREEN(row + 1, col)) != NULL)
508 command[comlen++] = 'j';
509 else if (dir == SOUTH
510 && strchr(PUSHOVER, SCREEN(row - 1, col)) != NULL)
511 command[comlen++] = 'k';
512 else if (dir == NORTH)
513 command[comlen++] = 'k';
514 else
515 command[comlen++] = 'j';
516 break;
517
518 case WEST:
519 case EAST:
520 if (strchr(PUSHOVER, SCREEN(row - 1, col)) != NULL)
521 command[comlen++] = 'k';
522 else if (strchr(PUSHOVER, SCREEN(row + 1, col)) != NULL)
523 command[comlen++] = 'j';
524 else if (dir == WEST
525 && strchr(PUSHOVER, SCREEN(row, col + 1)) != NULL)
526 command[comlen++] = 'l';
527 else if (dir == EAST
528 && strchr(PUSHOVER, SCREEN(row, col - 1)) != NULL)
529 command[comlen++] = 'h';
530 else if (dir == WEST)
531 command[comlen++] = 'h';
532 else
533 command[comlen++] = 'l';
534 break;
535 }
536 }
537
538 /*
539 * go for the closest mine if possible
540 */
541
542 STATIC int
543 go_for_ammo(mine)
544 char mine;
545 {
546 int i, rel_dir, dist;
547
548 rel_dir = -1;
549 dist = WIDTH;
550 for (i = 0; i < NUMDIRECTIONS; i++) {
551 if (flbr[i].what == mine && flbr[i].distance < dist) {
552 rel_dir = i;
553 dist = flbr[i].distance;
554 }
555 }
556 if (rel_dir == -1)
557 return FALSE;
558
559 if (!(flbr[rel_dir].flags & ON_SIDE)
560 || flbr[rel_dir].distance > 1) {
561 if (dist > 4)
562 dist = 4;
563 face_and_move_direction(rel_dir, dist);
564 } else
565 return FALSE; /* until it's done right */
566 return TRUE;
567 }
568
569 STATIC void
570 wander()
571 {
572 int i, j, rel_dir, dir_mask, dir_count;
573
574 for (i = 0; i < NUMDIRECTIONS; i++)
575 if (!(flbr[i].flags & BEEN) || flbr[i].distance <= 1)
576 break;
577 if (i == NUMDIRECTIONS)
578 memset(been_there, 0, sizeof been_there);
579 dir_mask = dir_count = 0;
580 for (i = 0; i < NUMDIRECTIONS; i++) {
581 j = (RIGHT + i) % NUMDIRECTIONS;
582 if (flbr[j].distance <= 1 || flbr[j].flags & DEADEND)
583 continue;
584 if (!(flbr[j].flags & BEEN_SAME)) {
585 dir_mask = 1 << j;
586 dir_count = 1;
587 break;
588 }
589 if (j == FRONT
590 && num_turns > 4 + (random() %
591 ((flbr[FRONT].flags & BEEN) ? 7 : HEIGHT)))
592 continue;
593 dir_mask |= 1 << j;
594 # ifdef notdef
595 dir_count++;
596 # else
597 dir_count = 1;
598 break;
599 # endif
600 }
601 if (dir_count == 0) {
602 duck(random() % NUMDIRECTIONS);
603 num_turns = 0;
604 return;
605 } else if (dir_count == 1)
606 rel_dir = ffs(dir_mask) - 1;
607 else {
608 rel_dir = ffs(dir_mask) - 1;
609 dir_mask &= ~(1 << rel_dir);
610 while (dir_mask != 0) {
611 i = ffs(dir_mask) - 1;
612 if (random() % 5 == 0)
613 rel_dir = i;
614 dir_mask &= ~(1 << i);
615 }
616 }
617 if (rel_dir == FRONT)
618 num_turns++;
619 else
620 num_turns = 0;
621
622 # ifdef DEBUG
623 fprintf(debug, " w(%c)", RELCHARS[rel_dir]);
624 # endif
625 face_and_move_direction(rel_dir, 1);
626 }
627
628 # endif /* OTTO */