/* $NetBSD: auto.c,v 1.11 2009/07/20 06:39:06 dholland Exp $ */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Christos Zoulas. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Automatic move. * intelligent ? * Algo : * IF scrapheaps don't exist THEN * IF not in danger THEN * stay at current position * ELSE * move away from the closest robot * FI * ELSE * find closest heap * find closest robot * IF scrapheap is adjacent THEN * move behind the scrapheap * ELSE * take the move that takes you away from the * robots and closest to the heap * FI * FI */ #include #include #include "robots.h" #define ABS(a) (((a)>0)?(a):-(a)) #define MIN(a,b) (((a)>(b))?(b):(a)) #define MAX(a,b) (((a)<(b))?(b):(a)) #define CONSDEBUG(a) static int distance(int, int, int, int); static int xinc(int); static int yinc(int); static const char *find_moves(void); static COORD *closest_robot(int *); static COORD *closest_heap(int *); static char move_towards(int, int); static char move_away(COORD *); static char move_between(COORD *, COORD *); static int between(COORD *, COORD *); /* distance(): * return "move" number distance of the two coordinates */ static int distance(int x1, int y1, int x2, int y2) { return MAX(ABS(ABS(x1) - ABS(x2)), ABS(ABS(y1) - ABS(y2))); } /* xinc(): * Return x coordinate moves */ static int xinc(int dir) { switch(dir) { case 'b': case 'h': case 'y': return -1; case 'l': case 'n': case 'u': return 1; case 'j': case 'k': default: return 0; } } /* yinc(): * Return y coordinate moves */ static int yinc(int dir) { switch(dir) { case 'k': case 'u': case 'y': return -1; case 'b': case 'j': case 'n': return 1; case 'h': case 'l': default: return 0; } } /* find_moves(): * Find possible moves */ static const char * find_moves(void) { int x, y; COORD test; const char *m; char *a; static const char moves[] = ".hjklyubn"; static char ans[sizeof moves]; a = ans; for (m = moves; *m; m++) { test.x = My_pos.x + xinc(*m); test.y = My_pos.y + yinc(*m); move(test.y, test.x); switch(winch(stdscr)) { case ' ': case PLAYER: for (x = test.x - 1; x <= test.x + 1; x++) { for (y = test.y - 1; y <= test.y + 1; y++) { move(y, x); if (winch(stdscr) == ROBOT) goto bad; } } *a++ = *m; } bad:; } *a = 0; if (ans[0]) return ans; else return "t"; } /* closest_robot(): * return the robot closest to us * and put in dist its distance */ static COORD * closest_robot(int *dist) { COORD *rob, *end, *minrob = NULL; int tdist, mindist; mindist = 1000000; end = &Robots[MAXROBOTS]; for (rob = Robots; rob < end; rob++) { tdist = distance(My_pos.x, My_pos.y, rob->x, rob->y); if (tdist < mindist) { minrob = rob; mindist = tdist; } } *dist = mindist; return minrob; } /* closest_heap(): * return the heap closest to us * and put in dist its distance */ static COORD * closest_heap(int *dist) { COORD *hp, *end, *minhp = NULL; int mindist, tdist; mindist = 1000000; end = &Scrap[MAXROBOTS]; for (hp = Scrap; hp < end; hp++) { if (hp->x == 0 && hp->y == 0) break; tdist = distance(My_pos.x, My_pos.y, hp->x, hp->y); if (tdist < mindist) { minhp = hp; mindist = tdist; } } *dist = mindist; return minhp; } /* move_towards(): * move as close to the given direction as possible */ static char move_towards(int dx, int dy) { char ok_moves[10], best_move; char *ptr; int move_judge, cur_judge, mvx, mvy; (void)strcpy(ok_moves, find_moves()); best_move = ok_moves[0]; if (best_move != 't') { mvx = xinc(best_move); mvy = yinc(best_move); move_judge = ABS(mvx - dx) + ABS(mvy - dy); for (ptr = &ok_moves[1]; *ptr != '\0'; ptr++) { mvx = xinc(*ptr); mvy = yinc(*ptr); cur_judge = ABS(mvx - dx) + ABS(mvy - dy); if (cur_judge < move_judge) { move_judge = cur_judge; best_move = *ptr; } } } return best_move; } /* move_away(): * move away form the robot given */ static char move_away(COORD *rob) { int dx, dy; dx = sign(My_pos.x - rob->x); dy = sign(My_pos.y - rob->y); return move_towards(dx, dy); } /* move_between(): * move the closest heap between us and the closest robot */ static char move_between(COORD *rob, COORD *hp) { int dx, dy; float slope, cons; /* equation of the line between us and the closest robot */ if (My_pos.x == rob->x) { /* * me and the robot are aligned in x * change my x so I get closer to the heap * and my y far from the robot */ dx = - sign(My_pos.x - hp->x); dy = sign(My_pos.y - rob->y); CONSDEBUG(("aligned in x")); } else if (My_pos.y == rob->y) { /* * me and the robot are aligned in y * change my y so I get closer to the heap * and my x far from the robot */ dx = sign(My_pos.x - rob->x); dy = -sign(My_pos.y - hp->y); CONSDEBUG(("aligned in y")); } else { CONSDEBUG(("no aligned")); slope = (My_pos.y - rob->y) / (My_pos.x - rob->x); cons = slope * rob->y; if (ABS(My_pos.x - rob->x) > ABS(My_pos.y - rob->y)) { /* * we are closest to the robot in x * move away from the robot in x and * close to the scrap in y */ dx = sign(My_pos.x - rob->x); dy = sign(((slope * ((float) hp->x)) + cons) - ((float) hp->y)); } else { dx = sign(((slope * ((float) hp->x)) + cons) - ((float) hp->y)); dy = sign(My_pos.y - rob->y); } } CONSDEBUG(("me (%d,%d) robot(%d,%d) heap(%d,%d) delta(%d,%d)", My_pos.x, My_pos.y, rob->x, rob->y, hp->x, hp->y, dx, dy)); return move_towards(dx, dy); } /* between(): * Return true if the heap is between us and the robot */ int between(COORD *rob, COORD *hp) { /* I = @ */ if (hp->x > rob->x && My_pos.x < rob->x) return 0; /* @ = I */ if (hp->x < rob->x && My_pos.x > rob->x) return 0; /* @ */ /* = */ /* I */ if (hp->y < rob->y && My_pos.y > rob->y) return 0; /* I */ /* = */ /* @ */ if (hp->y > rob->y && My_pos.y < rob->y) return 0; return 1; } /* automove(): * find and do the best move if flag * else get the first move; */ char automove(void) { #if 0 return find_moves()[0]; #else COORD *robot_close; COORD *heap_close; int robot_dist, robot_heap, heap_dist; robot_close = closest_robot(&robot_dist); if (robot_dist > 1) return('.'); if (!Num_scrap) /* no scrap heaps just run away */ return move_away(robot_close); heap_close = closest_heap(&heap_dist); robot_heap = distance(robot_close->x, robot_close->y, heap_close->x, heap_close->y); if (robot_heap <= heap_dist && !between(robot_close, heap_close)) { /* * robot is closest to us from the heap. Run away! */ return move_away(robot_close); } return move_between(robot_close, heap_close); #endif }