ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/maze_gen.C
Revision: 1.21
Committed: Tue Jun 29 16:52:53 2010 UTC (13 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.20: +59 -58 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 <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_max, seed_size;
66 static int xsize, ysize;
67 static char **maze;
68
69 static void
70 push (point p)
71 {
72 assert (seed_size < seed_max);
73
74 seed_list [seed_size++] = p;
75
76 maze [p.x][p.y] = '#';
77 }
78
79 /* the free wall points are those outer points which aren't corners or
80 near corners, and don't have a maze wall growing out of them already. */
81 static void
82 push_walls ()
83 {
84 /* top and bottom wall */
85 for (int x = 2; x < xsize - 2; x++)
86 {
87 push (point (x, 0));
88 push (point (x, ysize - 1));
89 }
90
91 /* left and right wall */
92 for (int y = 2; y < ysize - 2; y++)
93 {
94 push (point ( 0, y));
95 push (point (xsize - 1, y));
96 }
97 }
98
99 /* randomly returns one of the elements from the wall point list */
100 static point
101 pop_rand ()
102 {
103 int index = rmg_rndm (seed_size);
104
105 point p = seed_list [index];
106
107 /* write the last array point here */
108 seed_list [index] = seed_list [--seed_size];
109
110 return p;
111 }
112
113 /* find free point: randomly look for a square adjacent to this one where
114 we can place a new block without closing a path. We may only look
115 up, down, right, or left. */
116 static int
117 find_free_point (point &p, point pc)
118 {
119 /* we will randomly pick from this list, 1=up,2=down,3=right,4=left */
120 int dirlist[4];
121 int count = 0; /* # elements in dirlist */
122
123 int xc = pc.x;
124 int yc = pc.y;
125
126 /* look up */
127 if (yc < ysize - 2 && xc > 2 && xc < xsize - 2) /* it is valid to look up */
128 {
129 int cleartest = maze[xc][yc + 1] + maze[xc - 1][yc + 1] + maze[xc + 1][yc + 1]
130 + maze[xc][yc + 2] + maze[xc - 1][yc + 2] + maze[xc + 1][yc + 2];
131
132 if (cleartest == 0)
133 dirlist[count++] = 1;
134 }
135
136 /* look down */
137 if (yc > 2 && xc > 2 && xc < xsize - 2) /* it is valid to look down */
138 {
139 int cleartest = maze[xc][yc - 1] + maze[xc - 1][yc - 1] + maze[xc + 1][yc - 1]
140 + maze[xc][yc - 2] + maze[xc - 1][yc - 2] + maze[xc + 1][yc - 2];
141
142 if (cleartest == 0)
143 dirlist[count++] = 2;
144 }
145
146 /* look right */
147 if (xc < xsize - 2 && yc > 2 && yc < ysize - 2) /* it is valid to look left */
148 {
149 int cleartest = maze[xc + 1][yc] + maze[xc + 1][yc - 1] + maze[xc + 1][yc + 1]
150 + maze[xc + 2][yc] + maze[xc + 2][yc - 1] + maze[xc + 2][yc + 1];
151
152 if (cleartest == 0)
153 dirlist[count++] = 3;
154 }
155
156 /* look left */
157 if (xc > 2 && yc > 2 && yc < ysize - 2) /* it is valid to look down */
158 {
159 int cleartest = maze[xc - 1][yc] + maze[xc - 1][yc - 1] + maze[xc - 1][yc + 1]
160 + maze[xc - 2][yc] + maze[xc - 2][yc - 1] + maze[xc - 2][yc + 1];
161
162 if (cleartest == 0)
163 dirlist[count++] = 4;
164 }
165
166 if (count == 0)
167 return -1; /* failed to find any clear points */
168
169 /* choose a random direction */
170 switch (dirlist [rmg_rndm (count)])
171 {
172 case 1: /* up */
173 p.x = xc;
174 p.y = yc + 1;
175 break;
176
177 case 2: /* down */
178 p.x = xc;
179 p.y = yc - 1;
180 break;
181
182 case 3: /* right */
183 p.x = xc + 1;
184 p.y = yc;
185 break;
186
187 case 4: /* left */
188 p.x = xc - 1;
189 p.y = yc;
190 break;
191 }
192
193 return 1;
194 }
195
196 /* the outsize interface routine: accepts sizes, returns a char
197 ** maze. option is a flag for either a sparse or a full maze. Sparse
198 mazes have sizable rooms. option = 3=full, 2=braided, 1=sparse, 0=rooms.*/
199 void
200 maze_gen (Layout maze, int subtype)
201 {
202 xsize = maze->w;
203 ysize = maze->h;
204 ::maze = maze;
205
206 maze->clear ();
207 maze->border ();
208
209 if (xsize < 4 || ysize < 4)
210 return;
211
212 seed_max = xsize * ysize;
213 seed_size = 0;
214 seed_list = salloc<point> (seed_max);
215
216 if (subtype > 0)
217 push_walls ();
218
219 if (subtype == 0 || subtype == 2)
220 for (int i = (xsize + ysize) / 2; i; --i)
221 push (point (rmg_rndm (1, xsize - 2), rmg_rndm (1, ysize - 2)));
222
223 bool full = subtype == 3;
224
225 /* recursively generate the walls of the maze */
226 /* first pop a random starting point */
227 while (seed_size)
228 {
229 point p = pop_rand ();
230
231 for (;;)
232 {
233 point pc;
234
235 maze [p.x][p.y] = '#';
236
237 if (find_free_point (pc, p) < 0)
238 break;
239
240 if (full)
241 push (p);
242
243 if (!rmg_rndm (8))
244 {
245 if (!full)
246 push (pc);
247
248 break;
249 }
250
251 p = pc;
252 }
253 }
254
255 /* clean up our intermediate data structures. */
256 sfree (seed_list, seed_max);
257 }
258
259 #if 0
260 static struct demo
261 {
262 demo ()
263 {
264 Layout layout (30, 30);
265 rmg_rndm.seed (time (0));
266
267 for(int i=1;i<10;++i)
268 {
269 maze_gen (layout, 3);
270 layout.print ();
271 }
272 exit (1);
273 }
274 } demo;
275 #endif