ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/maze_gen.C
Revision: 1.4
Committed: Thu Sep 14 22:34:02 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.3: +0 -2 lines
Log Message:
indent

File Contents

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