ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/maze_gen.C
Revision: 1.12
Committed: Thu May 8 14:20:19 2008 UTC (16 years ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_82, rel-2_81, rel-2_80, rel-2_6, rel-2_7, rel-2_72, rel-2_73, rel-2_71, rel-2_76, rel-2_77, rel-2_74, rel-2_75, rel-2_54, rel-2_55, rel-2_56, rel-2_79, rel-2_78, rel-2_61
Changes since 1.11: +25 -47 lines
Log Message:
*** empty log message ***

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