xref: /netbsd/games/hunt/huntd/makemaze.c (revision 6550d01e)
1 /*	$NetBSD: makemaze.c,v 1.7 2009/08/12 07:42:11 dholland Exp $	*/
2 /*
3  * Copyright (c) 1983-2003, Regents of the University of California.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  * + Redistributions of source code must retain the above copyright
11  *   notice, this list of conditions and the following disclaimer.
12  * + Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  * + Neither the name of the University of California, San Francisco nor
16  *   the names of its contributors may be used to endorse or promote
17  *   products derived from this software without specific prior written
18  *   permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 #ifndef lint
35 __RCSID("$NetBSD: makemaze.c,v 1.7 2009/08/12 07:42:11 dholland Exp $");
36 #endif /* not lint */
37 
38 #include "hunt.h"
39 
40 #define ISCLEAR(y,x)	(Maze[y][x] == SPACE)
41 #define ODD(n)		((n) & 01)
42 
43 static int candig(int, int);
44 static void dig(int, int);
45 static void dig_maze(int, int);
46 static void remap(void);
47 
48 void
49 makemaze(void)
50 {
51 	char *sp;
52 	int y, x;
53 
54 	/*
55 	 * fill maze with walls
56 	 */
57 	sp = &Maze[0][0];
58 	while (sp < &Maze[HEIGHT - 1][WIDTH])
59 		*sp++ = DOOR;
60 
61 	x = rand_num(WIDTH / 2) * 2 + 1;
62 	y = rand_num(HEIGHT / 2) * 2 + 1;
63 	dig_maze(x, y);
64 	remap();
65 }
66 
67 #define NPERM	24
68 #define NDIR	4
69 
70 static int dirs[NPERM][NDIR] = {
71 	{0,1,2,3},	{3,0,1,2},	{0,2,3,1},	{0,3,2,1},
72 	{1,0,2,3},	{2,3,0,1},	{0,2,1,3},	{2,3,1,0},
73 	{1,0,3,2},	{1,2,0,3},	{3,1,2,0},	{2,0,3,1},
74 	{1,3,0,2},	{0,3,1,2},	{1,3,2,0},	{2,0,1,3},
75 	{0,1,3,2},	{3,1,0,2},	{2,1,0,3},	{1,2,3,0},
76 	{2,1,3,0},	{3,0,2,1},	{3,2,0,1},	{3,2,1,0}
77 };
78 
79 static int incr[NDIR][2] = {
80 	{0, 1}, {1, 0}, {0, -1}, {-1, 0}
81 };
82 
83 static void
84 dig(int y, int x)
85 {
86 	int *dp;
87 	int *ip;
88 	int ny, nx;
89 	int *endp;
90 
91 	Maze[y][x] = SPACE;			/* Clear this spot */
92 	dp = dirs[rand_num(NPERM)];
93 	endp = &dp[NDIR];
94 	while (dp < endp) {
95 		ip = &incr[*dp++][0];
96 		ny = y + *ip++;
97 		nx = x + *ip;
98 		if (candig(ny, nx))
99 			dig(ny, nx);
100 	}
101 }
102 
103 /*
104  * candig:
105  *	Is it legal to clear this spot?
106  */
107 static int
108 candig(int y, int x)
109 {
110 	int i;
111 
112 	if (ODD(x) && ODD(y))
113 		return FALSE;		/* can't touch ODD spots */
114 
115 	if (y < UBOUND || y >= DBOUND)
116 		return FALSE;		/* Beyond vertical bounds, NO */
117 	if (x < LBOUND || x >= RBOUND)
118 		return FALSE;		/* Beyond horizontal bounds, NO */
119 
120 	if (ISCLEAR(y, x))
121 		return FALSE;		/* Already clear, NO */
122 
123 	i = ISCLEAR(y, x + 1);
124 	i += ISCLEAR(y, x - 1);
125 	if (i > 1)
126 		return FALSE;		/* Introduces cycle, NO */
127 	i += ISCLEAR(y + 1, x);
128 	if (i > 1)
129 		return FALSE;		/* Introduces cycle, NO */
130 	i += ISCLEAR(y - 1, x);
131 	if (i > 1)
132 		return FALSE;		/* Introduces cycle, NO */
133 
134 	return TRUE;			/* OK */
135 }
136 
137 void
138 dig_maze(int x, int y)
139 {
140 	int tx, ty;
141 	int i, j;
142 	int order[4];
143 #define MNORTH	0x1
144 #define MSOUTH	0x2
145 #define MEAST	0x4
146 #define MWEST	0x8
147 
148 	tx = ty = 0;
149 	Maze[y][x] = SPACE;
150 	order[0] = MNORTH;
151 	for (i = 1; i < 4; i++) {
152 		j = rand_num(i + 1);
153 		order[i] = order[j];
154 		order[j] = 0x1 << i;
155 	}
156 	for (i = 0; i < 4; i++) {
157 		switch (order[i]) {
158 		  case MNORTH:
159 			tx = x;
160 			ty = y - 2;
161 			break;
162 		  case MSOUTH:
163 			tx = x;
164 			ty = y + 2;
165 			break;
166 		  case MEAST:
167 			tx = x + 2;
168 			ty = y;
169 			break;
170 		  case MWEST:
171 			tx = x - 2;
172 			ty = y;
173 			break;
174 		}
175 		if (tx < 0 || ty < 0 || tx >= WIDTH || ty >= HEIGHT)
176 			continue;
177 		if (Maze[ty][tx] == SPACE)
178 			continue;
179 		Maze[(y + ty) / 2][(x + tx) / 2] = SPACE;
180 		dig_maze(tx, ty);
181 	}
182 }
183 
184 void
185 remap(void)
186 {
187 	int y, x;
188 	char *sp;
189 	int stat;
190 
191 	for (y = 0; y < HEIGHT; y++)
192 		for (x = 0; x < WIDTH; x++) {
193 			sp = &Maze[y][x];
194 			if (*sp == SPACE)
195 				continue;
196 			stat = 0;
197 			if (y - 1 >= 0 && Maze[y - 1][x] != SPACE)
198 				stat |= NORTH;
199 			if (y + 1 < HEIGHT && Maze[y + 1][x] != SPACE)
200 				stat |= SOUTH;
201 			if (x + 1 < WIDTH && Maze[y][x + 1] != SPACE)
202 				stat |= EAST;
203 			if (x - 1 >= 0 && Maze[y][x - 1] != SPACE)
204 				stat |= WEST;
205 			switch (stat) {
206 			  case WEST | EAST:
207 			  case EAST:
208 			  case WEST:
209 				*sp = WALL1;
210 				break;
211 			  case NORTH | SOUTH:
212 			  case NORTH:
213 			  case SOUTH:
214 				*sp = WALL2;
215 				break;
216 			  case 0:
217 #ifdef RANDOM
218 				*sp = DOOR;
219 #endif
220 #ifdef REFLECT
221 				*sp = rand_num(2) ? WALL4 : WALL5;
222 #endif
223 				break;
224 			  default:
225 				*sp = WALL3;
226 				break;
227 			}
228 		}
229 	memcpy(Orig_maze, Maze, sizeof Maze);
230 }
231