ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/maze_gen.C
Revision: 1.3
Committed: Sun Sep 10 16:06:37 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.2: +188 -165 lines
Log Message:
indent

File Contents

# Content
1
2
3 /* peterm@langmuir.eecs.berkeley.edu: this function generates a random
4 blocked maze with the property that there is only one path from one spot
5 to any other, and there is always a path from one spot to any other.
6
7 input: xsize, ysize;
8 output: a char** array with # and . for closed and open respectively.
9
10 a char value of 0 represents a blank space: a '#' is
11 a wall.
12
13 */
14
15 /* we need to maintain a list of wall points to generate
16 reasonable mazes: a straightforward recursive random walk maze
17 generator would generate a map with a trivial circle-the-outer-wall solution */
18
19 #include <stdio.h>
20 #include <global.h>
21
22 /*#include <random_map.h>*/
23 #include <maze_gen.h>
24 #include <time.h>
25
26
27 /* this include solely, and only, is needed for the definition of RANDOM */
28
29
30
31 /* global variables that everyone needs: don't want to pass them in
32 as parameters every time. */
33 int *wall_x_list = 0;
34 int *wall_y_list = 0;
35 int wall_free_size = 0;
36
37 /* heuristically, we need to change wall_chance based on the size of
38 the maze. */
39
40 int wall_chance;
41
42 /* the outsize interface routine: accepts sizes, returns a char
43 ** maze. option is a flag for either a sparse or a full maze. Sparse
44 mazes have sizable rooms. option = 1, full, 0, sparse.*/
45
46 char **
47 maze_gen (int xsize, int ysize, int option)
48 {
49 int i, j;
50
51 /* allocate that array, set it up */
52 char **maze = (char **) calloc (sizeof (char *), xsize);
53
54 for (i = 0; i < xsize; i++)
55 {
56 maze[i] = (char *) calloc (sizeof (char), ysize);
57 }
58
59 /* write the outer walls */
60 for (i = 0; i < xsize; i++)
61 maze[i][0] = maze[i][ysize - 1] = '#';
62 for (j = 0; j < ysize; j++)
63 maze[0][j] = maze[xsize - 1][j] = '#';
64
65
66 /* find how many free wall spots there are */
67 wall_free_size = 2 * (xsize - 4) + 2 * (ysize - 4);
68
69 make_wall_free_list (xsize, ysize);
70
71 /* return the empty maze */
72 if (wall_free_size <= 0)
73 return maze;
74
75 /* recursively generate the walls of the maze */
76 /* first pop a random starting point */
77 while (wall_free_size > 0)
78 {
79 pop_wall_point (&i, &j);
80 if (option)
81 fill_maze_full (maze, i, j, xsize, ysize);
82 else
83 fill_maze_sparse (maze, i, j, xsize, ysize);
84 }
85
86 /* clean up our intermediate data structures. */
87
88 free (wall_x_list);
89 free (wall_y_list);
90
91 return maze;
92 }
93
94
95
96 /* the free wall points are those outer points which aren't corners or
97 near corners, and don't have a maze wall growing out of them already. */
98
99 void
100 make_wall_free_list (int xsize, int ysize)
101 {
102 int i, j, count;
103
104 count = 0; /* entries already placed in the free list */
105 /*allocate it */
106 if (wall_free_size < 0)
107 return;
108 wall_x_list = (int *) calloc (sizeof (int), wall_free_size);
109 wall_y_list = (int *) calloc (sizeof (int), wall_free_size);
110
111
112 /* top and bottom wall */
113 for (i = 2; i < xsize - 2; i++)
114 {
115 wall_x_list[count] = i;
116 wall_y_list[count] = 0;
117 count++;
118 wall_x_list[count] = i;
119 wall_y_list[count] = ysize - 1;
120 count++;
121 }
122
123 /* left and right wall */
124 for (j = 2; j < ysize - 2; j++)
125 {
126 wall_x_list[count] = 0;
127 wall_y_list[count] = j;
128 count++;
129 wall_x_list[count] = xsize - 1;
130 wall_y_list[count] = j;
131 count++;
132 }
133 }
134
135
136
137 /* randomly returns one of the elements from the wall point list */
138
139 void
140 pop_wall_point (int *x, int *y)
141 {
142 int index = RANDOM () % wall_free_size;
143
144 *x = wall_x_list[index];
145 *y = wall_y_list[index];
146 /* write the last array point here */
147 wall_x_list[index] = wall_x_list[wall_free_size - 1];
148 wall_y_list[index] = wall_y_list[wall_free_size - 1];
149 wall_free_size--;
150 }
151
152
153
154 /* find free point: randomly look for a square adjacent to this one where
155 we can place a new block without closing a path. We may only look
156 up, down, right, or left. */
157
158 int
159 find_free_point (char **maze, int *x, int *y, int xc, int yc, int xsize, int ysize)
160 {
161
162 /* we will randomly pick from this list, 1=up,2=down,3=right,4=left */
163 int dirlist[4];
164 int count = 0; /* # elements in dirlist */
165
166 /* look up */
167 if (yc < ysize - 2 && xc > 2 && xc < xsize - 2) /* it is valid to look up */
168 {
169 int cleartest = (int) maze[xc][yc + 1] + (int) maze[xc - 1][yc + 1] + (int) maze[xc + 1][yc + 1];
170
171 cleartest += (int) maze[xc][yc + 2] + (int) maze[xc - 1][yc + 2] + (int) maze[xc + 1][yc + 2];
172
173 if (cleartest == 0)
174 {
175 dirlist[count] = 1;
176 count++;
177 }
178 }
179
180
181 /* look down */
182 if (yc > 2 && xc > 2 && xc < xsize - 2) /* it is valid to look down */
183 {
184 int cleartest = (int) maze[xc][yc - 1] + (int) maze[xc - 1][yc - 1] + (int) maze[xc + 1][yc - 1];
185
186 cleartest += (int) maze[xc][yc - 2] + (int) maze[xc - 1][yc - 2] + (int) maze[xc + 1][yc - 2];
187
188 if (cleartest == 0)
189 {
190 dirlist[count] = 2;
191 count++;
192 }
193 }
194
195
196 /* look right */
197 if (xc < xsize - 2 && yc > 2 && yc < ysize - 2) /* it is valid to look left */
198 {
199 int cleartest = (int) maze[xc + 1][yc] + (int) maze[xc + 1][yc - 1] + (int) maze[xc + 1][yc + 1];
200
201 cleartest += (int) maze[xc + 2][yc] + (int) maze[xc + 2][yc - 1] + (int) maze[xc + 2][yc + 1];
202
203 if (cleartest == 0)
204 {
205 dirlist[count] = 3;
206 count++;
207 }
208 }
209
210
211 /* look left */
212 if (xc > 2 && yc > 2 && yc < ysize - 2) /* it is valid to look down */
213 {
214 int cleartest = (int) maze[xc - 1][yc] + (int) maze[xc - 1][yc - 1] + (int) maze[xc - 1][yc + 1];
215
216 cleartest += (int) maze[xc - 2][yc] + (int) maze[xc - 2][yc - 1] + (int) maze[xc - 2][yc + 1];
217
218 if (cleartest == 0)
219 {
220 dirlist[count] = 4;
221 count++;
222 }
223 }
224
225 if (count == 0)
226 return -1; /* failed to find any clear points */
227
228 /* choose a random direction */
229 if (count > 1)
230 count = RANDOM () % count;
231 else
232 count = 0;
233 switch (dirlist[count])
234 {
235 case 1: /* up */
236 {
237 *y = yc + 1;
238 *x = xc;
239 break;
240 };
241 case 2: /* down */
242 {
243 *y = yc - 1;
244 *x = xc;
245 break;
246 };
247 case 3: /* right */
248 {
249 *y = yc;
250 *x = xc + 1;
251 break;
252 }
253 case 4: /* left */
254 {
255 *x = xc - 1;
256 *y = yc;
257 break;
258 }
259 default: /* ??? */
260 {
261 return -1;
262 }
263 }
264 return 1;
265 }
266
267 /* recursive routine which will fill every available space in the maze
268 with walls*/
269
270 void
271 fill_maze_full (char **maze, int x, int y, int xsize, int ysize)
272 {
273 int xc, yc;
274
275 /* write a wall here */
276 maze[x][y] = '#';
277
278 /* decide if we're going to pick from the wall_free_list */
279 if (RANDOM () % 4 && wall_free_size > 0)
280 {
281 pop_wall_point (&xc, &yc);
282 fill_maze_full (maze, xc, yc, xsize, ysize);
283 }
284
285 /* change the if to a while for a complete maze. */
286 while (find_free_point (maze, &xc, &yc, x, y, xsize, ysize) != -1)
287 {
288 fill_maze_full (maze, xc, yc, xsize, ysize);
289 }
290 }
291
292
293 /* recursive routine which will fill much of the maze, but will leave
294 some free spots (possibly large) toward the center.*/
295
296 void
297 fill_maze_sparse (char **maze, int x, int y, int xsize, int ysize)
298 {
299 int xc, yc;
300
301 /* write a wall here */
302 maze[x][y] = '#';
303
304 /* decide if we're going to pick from the wall_free_list */
305 if (RANDOM () % 4 && wall_free_size > 0)
306 {
307 pop_wall_point (&xc, &yc);
308 fill_maze_sparse (maze, xc, yc, xsize, ysize);
309 }
310
311 /* change the if to a while for a complete maze. */
312 if (find_free_point (maze, &xc, &yc, x, y, xsize, ysize) != -1)
313 {
314 fill_maze_sparse (maze, xc, yc, xsize, ysize);
315 }
316 }