1*a4cc1f4fSdholland /* $NetBSD: auto.c,v 1.11 2009/07/20 06:39:06 dholland Exp $ */
218dfb39eSchristos
318dfb39eSchristos /*-
418dfb39eSchristos * Copyright (c) 1999 The NetBSD Foundation, Inc.
518dfb39eSchristos * All rights reserved.
618dfb39eSchristos *
718dfb39eSchristos * This code is derived from software contributed to The NetBSD Foundation
818dfb39eSchristos * by Christos Zoulas.
918dfb39eSchristos *
1018dfb39eSchristos * Redistribution and use in source and binary forms, with or without
1118dfb39eSchristos * modification, are permitted provided that the following conditions
1218dfb39eSchristos * are met:
1318dfb39eSchristos * 1. Redistributions of source code must retain the above copyright
1418dfb39eSchristos * notice, this list of conditions and the following disclaimer.
1518dfb39eSchristos * 2. Redistributions in binary form must reproduce the above copyright
1618dfb39eSchristos * notice, this list of conditions and the following disclaimer in the
1718dfb39eSchristos * documentation and/or other materials provided with the distribution.
1818dfb39eSchristos *
1918dfb39eSchristos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2018dfb39eSchristos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2118dfb39eSchristos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2218dfb39eSchristos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2318dfb39eSchristos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2418dfb39eSchristos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2518dfb39eSchristos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2618dfb39eSchristos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2718dfb39eSchristos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2818dfb39eSchristos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2918dfb39eSchristos * POSSIBILITY OF SUCH DAMAGE.
3018dfb39eSchristos */
3118dfb39eSchristos
3218dfb39eSchristos /*
3318dfb39eSchristos * Automatic move.
3418dfb39eSchristos * intelligent ?
3518dfb39eSchristos * Algo :
3618dfb39eSchristos * IF scrapheaps don't exist THEN
3718dfb39eSchristos * IF not in danger THEN
3804c4e386Schristos * stay at current position
3918dfb39eSchristos * ELSE
4018dfb39eSchristos * move away from the closest robot
4118dfb39eSchristos * FI
4218dfb39eSchristos * ELSE
4304c4e386Schristos * find closest heap
4404c4e386Schristos * find closest robot
4504c4e386Schristos * IF scrapheap is adjacent THEN
4604c4e386Schristos * move behind the scrapheap
4704c4e386Schristos * ELSE
4818dfb39eSchristos * take the move that takes you away from the
4918dfb39eSchristos * robots and closest to the heap
5018dfb39eSchristos * FI
5118dfb39eSchristos * FI
5218dfb39eSchristos */
53*a4cc1f4fSdholland #include <curses.h>
54*a4cc1f4fSdholland #include <string.h>
5518dfb39eSchristos #include "robots.h"
5618dfb39eSchristos
5718dfb39eSchristos #define ABS(a) (((a)>0)?(a):-(a))
5818dfb39eSchristos #define MIN(a,b) (((a)>(b))?(b):(a))
5918dfb39eSchristos #define MAX(a,b) (((a)<(b))?(b):(a))
6018dfb39eSchristos
6118dfb39eSchristos #define CONSDEBUG(a)
6218dfb39eSchristos
63cb5fd834Sjsm static int distance(int, int, int, int);
64cb5fd834Sjsm static int xinc(int);
65cb5fd834Sjsm static int yinc(int);
66cb5fd834Sjsm static const char *find_moves(void);
67cb5fd834Sjsm static COORD *closest_robot(int *);
68cb5fd834Sjsm static COORD *closest_heap(int *);
69cb5fd834Sjsm static char move_towards(int, int);
70cb5fd834Sjsm static char move_away(COORD *);
71cb5fd834Sjsm static char move_between(COORD *, COORD *);
72cb5fd834Sjsm static int between(COORD *, COORD *);
7318dfb39eSchristos
7418dfb39eSchristos /* distance():
7518dfb39eSchristos * return "move" number distance of the two coordinates
7618dfb39eSchristos */
7718dfb39eSchristos static int
distance(int x1,int y1,int x2,int y2)7830870bd5Sdholland distance(int x1, int y1, int x2, int y2)
7918dfb39eSchristos {
8018dfb39eSchristos return MAX(ABS(ABS(x1) - ABS(x2)), ABS(ABS(y1) - ABS(y2)));
8130870bd5Sdholland }
8218dfb39eSchristos
8318dfb39eSchristos /* xinc():
8418dfb39eSchristos * Return x coordinate moves
8518dfb39eSchristos */
8618dfb39eSchristos static int
xinc(int dir)8730870bd5Sdholland xinc(int dir)
8818dfb39eSchristos {
8918dfb39eSchristos switch(dir) {
9018dfb39eSchristos case 'b':
9118dfb39eSchristos case 'h':
9218dfb39eSchristos case 'y':
9318dfb39eSchristos return -1;
9418dfb39eSchristos case 'l':
9518dfb39eSchristos case 'n':
9618dfb39eSchristos case 'u':
9718dfb39eSchristos return 1;
9818dfb39eSchristos case 'j':
9918dfb39eSchristos case 'k':
10018dfb39eSchristos default:
10118dfb39eSchristos return 0;
10218dfb39eSchristos }
10318dfb39eSchristos }
10418dfb39eSchristos
10518dfb39eSchristos /* yinc():
10618dfb39eSchristos * Return y coordinate moves
10718dfb39eSchristos */
10818dfb39eSchristos static int
yinc(int dir)10930870bd5Sdholland yinc(int dir)
11018dfb39eSchristos {
11118dfb39eSchristos switch(dir) {
11218dfb39eSchristos case 'k':
11318dfb39eSchristos case 'u':
11418dfb39eSchristos case 'y':
11518dfb39eSchristos return -1;
11618dfb39eSchristos case 'b':
11718dfb39eSchristos case 'j':
11818dfb39eSchristos case 'n':
11918dfb39eSchristos return 1;
12018dfb39eSchristos case 'h':
12118dfb39eSchristos case 'l':
12218dfb39eSchristos default:
12318dfb39eSchristos return 0;
12418dfb39eSchristos }
12518dfb39eSchristos }
12618dfb39eSchristos
12718dfb39eSchristos /* find_moves():
12818dfb39eSchristos * Find possible moves
12918dfb39eSchristos */
130092d3130Sjsm static const char *
find_moves(void)13130870bd5Sdholland find_moves(void)
13218dfb39eSchristos {
13318dfb39eSchristos int x, y;
13418dfb39eSchristos COORD test;
135092d3130Sjsm const char *m;
136092d3130Sjsm char *a;
137092d3130Sjsm static const char moves[] = ".hjklyubn";
13818dfb39eSchristos static char ans[sizeof moves];
13918dfb39eSchristos a = ans;
14018dfb39eSchristos
14118dfb39eSchristos for (m = moves; *m; m++) {
14218dfb39eSchristos test.x = My_pos.x + xinc(*m);
14318dfb39eSchristos test.y = My_pos.y + yinc(*m);
14418dfb39eSchristos move(test.y, test.x);
14518dfb39eSchristos switch(winch(stdscr)) {
14618dfb39eSchristos case ' ':
14718dfb39eSchristos case PLAYER:
14818dfb39eSchristos for (x = test.x - 1; x <= test.x + 1; x++) {
14918dfb39eSchristos for (y = test.y - 1; y <= test.y + 1; y++) {
15018dfb39eSchristos move(y, x);
15118dfb39eSchristos if (winch(stdscr) == ROBOT)
15218dfb39eSchristos goto bad;
15318dfb39eSchristos }
15418dfb39eSchristos }
15518dfb39eSchristos *a++ = *m;
15618dfb39eSchristos }
15718dfb39eSchristos bad:;
15818dfb39eSchristos }
15918dfb39eSchristos *a = 0;
16018dfb39eSchristos if (ans[0])
161092d3130Sjsm return ans;
16218dfb39eSchristos else
163092d3130Sjsm return "t";
16418dfb39eSchristos }
16518dfb39eSchristos
16618dfb39eSchristos /* closest_robot():
16718dfb39eSchristos * return the robot closest to us
16818dfb39eSchristos * and put in dist its distance
16918dfb39eSchristos */
17018dfb39eSchristos static COORD *
closest_robot(int * dist)17130870bd5Sdholland closest_robot(int *dist)
17218dfb39eSchristos {
173605ec8abSchristos COORD *rob, *end, *minrob = NULL;
17418dfb39eSchristos int tdist, mindist;
17518dfb39eSchristos
17618dfb39eSchristos mindist = 1000000;
17718dfb39eSchristos end = &Robots[MAXROBOTS];
17818dfb39eSchristos for (rob = Robots; rob < end; rob++) {
17918dfb39eSchristos tdist = distance(My_pos.x, My_pos.y, rob->x, rob->y);
18018dfb39eSchristos if (tdist < mindist) {
18118dfb39eSchristos minrob = rob;
18218dfb39eSchristos mindist = tdist;
18318dfb39eSchristos }
18418dfb39eSchristos }
18518dfb39eSchristos *dist = mindist;
18618dfb39eSchristos return minrob;
18730870bd5Sdholland }
18818dfb39eSchristos
18918dfb39eSchristos /* closest_heap():
19018dfb39eSchristos * return the heap closest to us
19118dfb39eSchristos * and put in dist its distance
19218dfb39eSchristos */
19318dfb39eSchristos static COORD *
closest_heap(int * dist)19430870bd5Sdholland closest_heap(int *dist)
19518dfb39eSchristos {
196605ec8abSchristos COORD *hp, *end, *minhp = NULL;
19718dfb39eSchristos int mindist, tdist;
19818dfb39eSchristos
19918dfb39eSchristos mindist = 1000000;
20018dfb39eSchristos end = &Scrap[MAXROBOTS];
20118dfb39eSchristos for (hp = Scrap; hp < end; hp++) {
20218dfb39eSchristos if (hp->x == 0 && hp->y == 0)
20318dfb39eSchristos break;
20418dfb39eSchristos tdist = distance(My_pos.x, My_pos.y, hp->x, hp->y);
20518dfb39eSchristos if (tdist < mindist) {
20618dfb39eSchristos minhp = hp;
20718dfb39eSchristos mindist = tdist;
20818dfb39eSchristos }
20918dfb39eSchristos }
21018dfb39eSchristos *dist = mindist;
21118dfb39eSchristos return minhp;
21230870bd5Sdholland }
21318dfb39eSchristos
21418dfb39eSchristos /* move_towards():
21518dfb39eSchristos * move as close to the given direction as possible
21618dfb39eSchristos */
21718dfb39eSchristos static char
move_towards(int dx,int dy)21830870bd5Sdholland move_towards(int dx, int dy)
21918dfb39eSchristos {
22018dfb39eSchristos char ok_moves[10], best_move;
22118dfb39eSchristos char *ptr;
22218dfb39eSchristos int move_judge, cur_judge, mvx, mvy;
22318dfb39eSchristos
22418dfb39eSchristos (void)strcpy(ok_moves, find_moves());
22518dfb39eSchristos best_move = ok_moves[0];
226fc92c2f7Schristos if (best_move != 't') {
22718dfb39eSchristos mvx = xinc(best_move);
22818dfb39eSchristos mvy = yinc(best_move);
22918dfb39eSchristos move_judge = ABS(mvx - dx) + ABS(mvy - dy);
23018dfb39eSchristos for (ptr = &ok_moves[1]; *ptr != '\0'; ptr++) {
23118dfb39eSchristos mvx = xinc(*ptr);
23218dfb39eSchristos mvy = yinc(*ptr);
23318dfb39eSchristos cur_judge = ABS(mvx - dx) + ABS(mvy - dy);
23418dfb39eSchristos if (cur_judge < move_judge) {
23518dfb39eSchristos move_judge = cur_judge;
23618dfb39eSchristos best_move = *ptr;
23718dfb39eSchristos }
23818dfb39eSchristos }
23918dfb39eSchristos }
24018dfb39eSchristos return best_move;
24130870bd5Sdholland }
24218dfb39eSchristos
24318dfb39eSchristos /* move_away():
24418dfb39eSchristos * move away form the robot given
24518dfb39eSchristos */
24618dfb39eSchristos static char
move_away(COORD * rob)24730870bd5Sdholland move_away(COORD *rob)
24818dfb39eSchristos {
24918dfb39eSchristos int dx, dy;
25018dfb39eSchristos
25118dfb39eSchristos dx = sign(My_pos.x - rob->x);
25218dfb39eSchristos dy = sign(My_pos.y - rob->y);
25318dfb39eSchristos return move_towards(dx, dy);
25430870bd5Sdholland }
25518dfb39eSchristos
25618dfb39eSchristos
25718dfb39eSchristos /* move_between():
25818dfb39eSchristos * move the closest heap between us and the closest robot
25918dfb39eSchristos */
26018dfb39eSchristos static char
move_between(COORD * rob,COORD * hp)26130870bd5Sdholland move_between(COORD *rob, COORD *hp)
26218dfb39eSchristos {
2634cb49d76Schristos int dx, dy;
26418dfb39eSchristos float slope, cons;
26518dfb39eSchristos
26618dfb39eSchristos /* equation of the line between us and the closest robot */
26718dfb39eSchristos if (My_pos.x == rob->x) {
26818dfb39eSchristos /*
26918dfb39eSchristos * me and the robot are aligned in x
27018dfb39eSchristos * change my x so I get closer to the heap
27118dfb39eSchristos * and my y far from the robot
27218dfb39eSchristos */
27318dfb39eSchristos dx = - sign(My_pos.x - hp->x);
27418dfb39eSchristos dy = sign(My_pos.y - rob->y);
27518dfb39eSchristos CONSDEBUG(("aligned in x"));
27618dfb39eSchristos }
27718dfb39eSchristos else if (My_pos.y == rob->y) {
27818dfb39eSchristos /*
27918dfb39eSchristos * me and the robot are aligned in y
28018dfb39eSchristos * change my y so I get closer to the heap
28118dfb39eSchristos * and my x far from the robot
28218dfb39eSchristos */
28318dfb39eSchristos dx = sign(My_pos.x - rob->x);
28418dfb39eSchristos dy = -sign(My_pos.y - hp->y);
28518dfb39eSchristos CONSDEBUG(("aligned in y"));
28618dfb39eSchristos }
28718dfb39eSchristos else {
28818dfb39eSchristos CONSDEBUG(("no aligned"));
28918dfb39eSchristos slope = (My_pos.y - rob->y) / (My_pos.x - rob->x);
29018dfb39eSchristos cons = slope * rob->y;
29118dfb39eSchristos if (ABS(My_pos.x - rob->x) > ABS(My_pos.y - rob->y)) {
29218dfb39eSchristos /*
29318dfb39eSchristos * we are closest to the robot in x
29418dfb39eSchristos * move away from the robot in x and
29518dfb39eSchristos * close to the scrap in y
29618dfb39eSchristos */
29718dfb39eSchristos dx = sign(My_pos.x - rob->x);
29818dfb39eSchristos dy = sign(((slope * ((float) hp->x)) + cons) -
29918dfb39eSchristos ((float) hp->y));
30018dfb39eSchristos }
30118dfb39eSchristos else {
30218dfb39eSchristos dx = sign(((slope * ((float) hp->x)) + cons) -
30318dfb39eSchristos ((float) hp->y));
30418dfb39eSchristos dy = sign(My_pos.y - rob->y);
30518dfb39eSchristos }
30618dfb39eSchristos }
30718dfb39eSchristos CONSDEBUG(("me (%d,%d) robot(%d,%d) heap(%d,%d) delta(%d,%d)",
30818dfb39eSchristos My_pos.x, My_pos.y, rob->x, rob->y, hp->x, hp->y, dx, dy));
30918dfb39eSchristos return move_towards(dx, dy);
31030870bd5Sdholland }
31118dfb39eSchristos
31218dfb39eSchristos /* between():
31318dfb39eSchristos * Return true if the heap is between us and the robot
31418dfb39eSchristos */
31518dfb39eSchristos int
between(COORD * rob,COORD * hp)31630870bd5Sdholland between(COORD *rob, COORD *hp)
31718dfb39eSchristos {
31818dfb39eSchristos /* I = @ */
31918dfb39eSchristos if (hp->x > rob->x && My_pos.x < rob->x)
32018dfb39eSchristos return 0;
32118dfb39eSchristos /* @ = I */
32218dfb39eSchristos if (hp->x < rob->x && My_pos.x > rob->x)
32318dfb39eSchristos return 0;
32418dfb39eSchristos /* @ */
32518dfb39eSchristos /* = */
32618dfb39eSchristos /* I */
32718dfb39eSchristos if (hp->y < rob->y && My_pos.y > rob->y)
32818dfb39eSchristos return 0;
32918dfb39eSchristos /* I */
33018dfb39eSchristos /* = */
33118dfb39eSchristos /* @ */
33218dfb39eSchristos if (hp->y > rob->y && My_pos.y < rob->y)
33318dfb39eSchristos return 0;
33418dfb39eSchristos return 1;
33530870bd5Sdholland }
33618dfb39eSchristos
33718dfb39eSchristos /* automove():
33818dfb39eSchristos * find and do the best move if flag
33918dfb39eSchristos * else get the first move;
34018dfb39eSchristos */
34118dfb39eSchristos char
automove(void)34230870bd5Sdholland automove(void)
34318dfb39eSchristos {
34418dfb39eSchristos #if 0
34518dfb39eSchristos return find_moves()[0];
34618dfb39eSchristos #else
34718dfb39eSchristos COORD *robot_close;
34818dfb39eSchristos COORD *heap_close;
34918dfb39eSchristos int robot_dist, robot_heap, heap_dist;
35018dfb39eSchristos
35118dfb39eSchristos robot_close = closest_robot(&robot_dist);
35218dfb39eSchristos if (robot_dist > 1)
35318dfb39eSchristos return('.');
35418dfb39eSchristos if (!Num_scrap)
35518dfb39eSchristos /* no scrap heaps just run away */
35618dfb39eSchristos return move_away(robot_close);
35718dfb39eSchristos
35818dfb39eSchristos heap_close = closest_heap(&heap_dist);
35918dfb39eSchristos robot_heap = distance(robot_close->x, robot_close->y,
36018dfb39eSchristos heap_close->x, heap_close->y);
36118dfb39eSchristos if (robot_heap <= heap_dist && !between(robot_close, heap_close)) {
36218dfb39eSchristos /*
36318dfb39eSchristos * robot is closest to us from the heap. Run away!
36418dfb39eSchristos */
36518dfb39eSchristos return move_away(robot_close);
36618dfb39eSchristos }
36718dfb39eSchristos
36818dfb39eSchristos return move_between(robot_close, heap_close);
36918dfb39eSchristos #endif
37030870bd5Sdholland }
371