ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/maze_gen.C
Revision: 1.20
Committed: Sun Jun 27 20:40:54 2010 UTC (13 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.19: +76 -88 lines
Log Message:
prepare for greatness that might never come

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