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