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, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.4: +29 -28 lines
Log Message:
reindent, minor changes

File Contents

# User Rev Content
1 root 1.5
2 elmex 1.1 /* 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 root 1.3
21 elmex 1.1 /*#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 root 1.3 int *wall_x_list = 0;
33     int *wall_y_list = 0;
34     int wall_free_size = 0;
35 elmex 1.1
36     /* heuristically, we need to change wall_chance based on the size of
37     the maze. */
38    
39 root 1.3 int wall_chance;
40 elmex 1.1
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 root 1.3 char **
46     maze_gen (int xsize, int ysize, int option)
47     {
48     int i, j;
49 elmex 1.1
50     /* allocate that array, set it up */
51 root 1.3 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 elmex 1.1
58     /* write the outer walls */
59 root 1.3 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 elmex 1.1 /* find how many free wall spots there are */
66 root 1.3 wall_free_size = 2 * (xsize - 4) + 2 * (ysize - 4);
67    
68     make_wall_free_list (xsize, ysize);
69 elmex 1.1
70     /* return the empty maze */
71 root 1.3 if (wall_free_size <= 0)
72     return maze;
73 elmex 1.1
74     /* recursively generate the walls of the maze */
75     /* first pop a random starting point */
76 root 1.3 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 elmex 1.1
85     /* clean up our intermediate data structures. */
86 root 1.3
87     free (wall_x_list);
88     free (wall_y_list);
89 elmex 1.1
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 root 1.3 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 elmex 1.1
111     /* top and bottom wall */
112 root 1.3 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 elmex 1.1
122     /* left and right wall */
123 root 1.3 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 elmex 1.1 }
133    
134    
135    
136     /* randomly returns one of the elements from the wall point list */
137    
138 root 1.3 void
139     pop_wall_point (int *x, int *y)
140     {
141     int index = RANDOM () % wall_free_size;
142    
143 elmex 1.1 *x = wall_x_list[index];
144     *y = wall_y_list[index];
145     /* write the last array point here */
146 root 1.3 wall_x_list[index] = wall_x_list[wall_free_size - 1];
147     wall_y_list[index] = wall_y_list[wall_free_size - 1];
148 elmex 1.1 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 root 1.3 int
158     find_free_point (char **maze, int *x, int *y, int xc, int yc, int xsize, int ysize)
159     {
160 elmex 1.1
161     /* we will randomly pick from this list, 1=up,2=down,3=right,4=left */
162 root 1.3 int dirlist[4];
163     int count = 0; /* # elements in dirlist */
164 elmex 1.1
165     /* look up */
166 root 1.3 if (yc < ysize - 2 && xc > 2 && xc < xsize - 2) /* it is valid to look up */
167 elmex 1.1 {
168 root 1.3 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 elmex 1.1 }
178    
179    
180     /* look down */
181 root 1.3 if (yc > 2 && xc > 2 && xc < xsize - 2) /* it is valid to look down */
182 elmex 1.1 {
183 root 1.3 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 elmex 1.1 }
193    
194    
195     /* look right */
196 root 1.3 if (xc < xsize - 2 && yc > 2 && yc < ysize - 2) /* it is valid to look left */
197 elmex 1.1 {
198 root 1.3 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 elmex 1.1 }
208    
209    
210     /* look left */
211 root 1.3 if (xc > 2 && yc > 2 && yc < ysize - 2) /* it is valid to look down */
212 elmex 1.1 {
213 root 1.3 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 root 1.2
217 root 1.3 if (cleartest == 0)
218     {
219     dirlist[count] = 4;
220     count++;
221     }
222 elmex 1.1 }
223    
224 root 1.3 if (count == 0)
225     return -1; /* failed to find any clear points */
226 elmex 1.1
227     /* choose a random direction */
228 root 1.3 if (count > 1)
229     count = RANDOM () % count;
230     else
231     count = 0;
232     switch (dirlist[count])
233 elmex 1.1 {
234 root 1.5 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 elmex 1.1 }
263     return 1;
264     }
265    
266     /* recursive routine which will fill every available space in the maze
267 root 1.3 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 elmex 1.1
274     /* write a wall here */
275     maze[x][y] = '#';
276 root 1.3
277 elmex 1.1 /* decide if we're going to pick from the wall_free_list */
278 root 1.3 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 elmex 1.1 }
290    
291    
292     /* recursive routine which will fill much of the maze, but will leave
293 root 1.2 some free spots (possibly large) toward the center.*/
294 elmex 1.1
295 root 1.3 void
296     fill_maze_sparse (char **maze, int x, int y, int xsize, int ysize)
297     {
298     int xc, yc;
299    
300 elmex 1.1 /* write a wall here */
301     maze[x][y] = '#';
302 root 1.3
303 elmex 1.1 /* decide if we're going to pick from the wall_free_list */
304 root 1.3 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 elmex 1.1 }