xref: /netbsd-src/games/robots/auto.c (revision a4cc1f4f0637905f7929d8a1548fb2e9be0fa870)
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