ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/maze_gen.C
Revision: 1.19
Committed: Sun Jun 27 16:36:12 2010 UTC (13 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.18: +16 -12 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 /*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2005,2006,2007,2008,2009 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) Crossfire Development Team (restored, original file without copyright notice)
6 *
7 * Deliantra is free software: you can redistribute it and/or modify it under
8 * the terms of the Affero GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the Affero GNU General Public License
18 * and the GNU General Public License along with this program. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 * The authors can be reached via e-mail to <support@deliantra.net>
22 */
23
24 /* peterm@langmuir.eecs.berkeley.edu: this function generates a random
25 blocked maze with the property that there is only one path from one spot
26 to any other, and there is always a path from one spot to any other.
27
28 input: xsize, ysize;
29 output: a char** array with # and . for closed and open respectively.
30
31 a char value of 0 represents a blank space: a '#' is
32 a wall.
33
34 */
35
36 /* we need to maintain a list of wall points to generate
37 reasonable mazes: a straightforward recursive random walk maze
38 generator would generate a map with a trivial circle-the-outer-wall solution */
39
40 #include <global.h>
41
42 #include "random_map.h"
43 #include "rproto.h"
44
45 /* global variables that everyone needs: don't want to pass them in
46 as parameters every time. */
47 static int *wall_x_list = 0;
48 static int *wall_y_list = 0;
49 static int wall_free_size = 0;
50 static int xsize, ysize;
51
52 /* the free wall points are those outer points which aren't corners or
53 near corners, and don't have a maze wall growing out of them already. */
54 static void
55 make_wall_free_list (int xsize, int ysize)
56 {
57 int i, j, count;
58
59 count = 0; /* entries already placed in the free list */
60 /*allocate it */
61 if (wall_free_size < 0)
62 return;
63
64 wall_x_list = (int *)calloc (sizeof (int), wall_free_size);
65 wall_y_list = (int *)calloc (sizeof (int), wall_free_size);
66
67 /* top and bottom wall */
68 for (i = 2; i < xsize - 2; i++)
69 {
70 wall_x_list[count] = i;
71 wall_y_list[count] = 0;
72 count++;
73 wall_x_list[count] = i;
74 wall_y_list[count] = ysize - 1;
75 count++;
76 }
77
78 /* left and right wall */
79 for (j = 2; j < ysize - 2; j++)
80 {
81 wall_x_list[count] = 0;
82 wall_y_list[count] = j;
83 count++;
84 wall_x_list[count] = xsize - 1;
85 wall_y_list[count] = j;
86 count++;
87 }
88 }
89
90 /* randomly returns one of the elements from the wall point list */
91 static void
92 pop_wall_point (int *x, int *y)
93 {
94 int index = rmg_rndm (wall_free_size);
95
96 *x = wall_x_list[index];
97 *y = wall_y_list[index];
98
99 /* write the last array point here */
100 wall_x_list[index] = wall_x_list[wall_free_size - 1];
101 wall_y_list[index] = wall_y_list[wall_free_size - 1];
102 wall_free_size--;
103 }
104
105 /* find free point: randomly look for a square adjacent to this one where
106 we can place a new block without closing a path. We may only look
107 up, down, right, or left. */
108 static int
109 find_free_point (char **maze, int *x, int *y, int xc, int yc)
110 {
111 /* we will randomly pick from this list, 1=up,2=down,3=right,4=left */
112 int dirlist[4];
113 int count = 0; /* # elements in dirlist */
114
115 /* look up */
116 if (yc < ysize - 2 && xc > 2 && xc < xsize - 2) /* it is valid to look up */
117 {
118 int cleartest = maze[xc][yc + 1] + maze[xc - 1][yc + 1] + maze[xc + 1][yc + 1]
119 + maze[xc][yc + 2] + maze[xc - 1][yc + 2] + maze[xc + 1][yc + 2];
120
121 if (cleartest == 0)
122 dirlist[count++] = 1;
123 }
124
125 /* look down */
126 if (yc > 2 && xc > 2 && xc < xsize - 2) /* it is valid to look down */
127 {
128 int cleartest = maze[xc][yc - 1] + maze[xc - 1][yc - 1] + maze[xc + 1][yc - 1]
129 + maze[xc][yc - 2] + maze[xc - 1][yc - 2] + maze[xc + 1][yc - 2];
130
131 if (cleartest == 0)
132 dirlist[count++] = 2;
133 }
134
135 /* look right */
136 if (xc < xsize - 2 && yc > 2 && yc < ysize - 2) /* it is valid to look left */
137 {
138 int cleartest = maze[xc + 1][yc] + maze[xc + 1][yc - 1] + maze[xc + 1][yc + 1]
139 + maze[xc + 2][yc] + maze[xc + 2][yc - 1] + maze[xc + 2][yc + 1];
140
141 if (cleartest == 0)
142 dirlist[count++] = 3;
143 }
144
145 /* look left */
146 if (xc > 2 && yc > 2 && yc < ysize - 2) /* it is valid to look down */
147 {
148 int cleartest = maze[xc - 1][yc] + maze[xc - 1][yc - 1] + maze[xc - 1][yc + 1]
149 + maze[xc - 2][yc] + maze[xc - 2][yc - 1] + maze[xc - 2][yc + 1];
150
151 if (cleartest == 0)
152 dirlist[count++] = 4;
153 }
154
155 if (count == 0)
156 return -1; /* failed to find any clear points */
157
158 /* choose a random direction */
159 switch (dirlist [rmg_rndm (count)])
160 {
161 case 1: /* up */
162 *y = yc + 1;
163 *x = xc;
164 break;
165
166 case 2: /* down */
167 *y = yc - 1;
168 *x = xc;
169 break;
170
171 case 3: /* right */
172 *y = yc;
173 *x = xc + 1;
174 break;
175
176 case 4: /* left */
177 *x = xc - 1;
178 *y = yc;
179 break;
180 }
181
182 return 1;
183 }
184
185 /* recursive routine which will fill every available space in the maze
186 with walls*/
187 static void
188 fill_maze_full (char **maze, int x, int y)
189 {
190 int xc, yc;
191
192 /* write a wall here */
193 maze[x][y] = '#';
194
195 /* decide if we're going to pick from the wall_free_list */
196 if (rmg_rndm (2) && wall_free_size > 0)
197 {
198 pop_wall_point (&xc, &yc);
199 fill_maze_full (maze, xc, yc);
200 }
201
202 /* change the while to an if for a sparse maze. */
203 while (find_free_point (maze, &xc, &yc, x, y) != -1)
204 fill_maze_full (maze, xc, yc);
205 }
206
207 /* recursive routine which will fill much of the maze, but will leave
208 some free spots (possibly large) toward the center.*/
209 static void
210 fill_maze_sparse (char **maze, int x, int y)
211 {
212 int xc, yc;
213
214 /* write a wall here */
215 maze[x][y] = '#';
216
217 /* decide if we're going to pick from the wall_free_list */
218 if (rmg_rndm (2) && wall_free_size > 0)
219 {
220 pop_wall_point (&xc, &yc);
221 fill_maze_sparse (maze, xc, yc);
222 }
223
224 /* change the if to a while for a complete maze. */
225 if (find_free_point (maze, &xc, &yc, x, y) != -1)
226 fill_maze_sparse (maze, xc, yc);
227 }
228
229 /* the outsize interface routine: accepts sizes, returns a char
230 ** maze. option is a flag for either a sparse or a full maze. Sparse
231 mazes have sizable rooms. option = 1, full, 0, sparse.*/
232 void
233 maze_gen (Layout maze, int full)
234 {
235 maze->clear ();
236 maze->border ();
237
238 xsize = maze->w;
239 ysize = maze->h;
240
241 /* find how many free wall spots there are */
242 wall_free_size = 2 * (maze->w - 4) + 2 * (maze->h - 4);
243
244 make_wall_free_list (maze->w, maze->h);
245
246 /* return the empty maze */
247 if (wall_free_size <= 0)
248 return;
249
250 /* recursively generate the walls of the maze */
251 /* first pop a random starting point */
252 while (wall_free_size > 0)
253 {
254 int i, j;
255
256 pop_wall_point (&i, &j);
257
258 if (full)
259 fill_maze_full (maze, i, j);
260 else
261 fill_maze_sparse (maze, i, j);
262 }
263
264 /* clean up our intermediate data structures. */
265
266 free (wall_x_list);
267 free (wall_y_list);
268 }
269
270 #if 1
271 static struct demo
272 {
273 demo ()
274 {
275 Layout layout (30, 30);
276 rmg_rndm.seed (time (0));
277
278 for(int i=1;i<10;++i)
279 {
280 maze_gen (layout, 1);
281 layout.print ();
282 }
283 exit (1);
284 }
285 } demo;
286 #endif