ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/maze_gen.C
Revision: 1.5
Committed: Sun Dec 31 19:02:24 2006 UTC (17 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.4: +29 -28 lines
Log Message:
reindent, minor changes

File Contents

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