ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/maze_gen.C
Revision: 1.7
Committed: Sat Jan 27 02:19:37 2007 UTC (17 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_4, rel-2_2, rel-2_3, rel-2_0, rel-2_1, rel-2_32, rel-2_43, rel-2_42, rel-2_41
Changes since 1.6: +3 -7 lines
Log Message:
- experimentall.y determine minimum random map size (12)
- harden random map generator by stresstesting
- reduced codesize while increasing readability (RANDOM => rndm)
- fixed a likely unimportant bug in random_roll64
- possibly broke lots of code

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