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

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