ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/maze_gen.C
Revision: 1.23
Committed: Wed Jun 30 20:51:02 2010 UTC (13 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.22: +12 -58 lines
Log Message:
implement isolation remover, moved layout functions to their own file

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 /* global variables that everyone needs: don't want to pass them in
48 as parameters every time. */
49 static fixed_stack<point> seeds;
50 static int xsize, ysize;
51 static char **maze;
52
53 static void
54 push (point p)
55 {
56 seeds.push (p);
57 maze [p.x][p.y] = '#';
58 }
59
60 /* randomly returns one of the elements from the wall point list */
61 static point
62 pop_rand ()
63 {
64 return seeds.remove (rmg_rndm (seeds.size));
65 }
66
67 /* the free wall points are those outer points which aren't corners or
68 near corners, and don't have a maze wall growing out of them already. */
69 static void
70 push_walls ()
71 {
72 /* top and bottom wall */
73 for (int x = 2; x < xsize - 2; x++)
74 {
75 push (point (x, 0));
76 push (point (x, ysize - 1));
77 }
78
79 /* left and right wall */
80 for (int y = 2; y < ysize - 2; y++)
81 {
82 push (point ( 0, y));
83 push (point (xsize - 1, y));
84 }
85 }
86
87 /* find free point: randomly look for a square adjacent to this one where
88 we can place a new block without closing a path. We may only look
89 up, down, right, or left. */
90 static int
91 find_free_point (point &p, point pc)
92 {
93 /* we will randomly pick from this list, 1=up,2=down,3=right,4=left */
94 int dirlist[4];
95 int count = 0; /* # elements in dirlist */
96
97 int xc = pc.x;
98 int yc = pc.y;
99
100 /* look up */
101 if (yc < ysize - 2 && xc > 2 && xc < xsize - 2) /* it is valid to look up */
102 {
103 int cleartest = maze[xc][yc + 1] + maze[xc - 1][yc + 1] + maze[xc + 1][yc + 1]
104 + maze[xc][yc + 2] + maze[xc - 1][yc + 2] + maze[xc + 1][yc + 2];
105
106 if (cleartest == 0)
107 dirlist[count++] = 1;
108 }
109
110 /* look down */
111 if (yc > 2 && xc > 2 && xc < xsize - 2) /* it is valid to look down */
112 {
113 int cleartest = maze[xc][yc - 1] + maze[xc - 1][yc - 1] + maze[xc + 1][yc - 1]
114 + maze[xc][yc - 2] + maze[xc - 1][yc - 2] + maze[xc + 1][yc - 2];
115
116 if (cleartest == 0)
117 dirlist[count++] = 2;
118 }
119
120 /* look right */
121 if (xc < xsize - 2 && yc > 2 && yc < ysize - 2) /* it is valid to look left */
122 {
123 int cleartest = maze[xc + 1][yc] + maze[xc + 1][yc - 1] + maze[xc + 1][yc + 1]
124 + maze[xc + 2][yc] + maze[xc + 2][yc - 1] + maze[xc + 2][yc + 1];
125
126 if (cleartest == 0)
127 dirlist[count++] = 3;
128 }
129
130 /* look left */
131 if (xc > 2 && yc > 2 && yc < ysize - 2) /* it is valid to look down */
132 {
133 int cleartest = maze[xc - 1][yc] + maze[xc - 1][yc - 1] + maze[xc - 1][yc + 1]
134 + maze[xc - 2][yc] + maze[xc - 2][yc - 1] + maze[xc - 2][yc + 1];
135
136 if (cleartest == 0)
137 dirlist[count++] = 4;
138 }
139
140 if (count == 0)
141 return -1; /* failed to find any clear points */
142
143 /* choose a random direction */
144 switch (dirlist [rmg_rndm (count)])
145 {
146 case 1: /* up */
147 p.x = xc;
148 p.y = yc + 1;
149 break;
150
151 case 2: /* down */
152 p.x = xc;
153 p.y = yc - 1;
154 break;
155
156 case 3: /* right */
157 p.x = xc + 1;
158 p.y = yc;
159 break;
160
161 case 4: /* left */
162 p.x = xc - 1;
163 p.y = yc;
164 break;
165 }
166
167 return 1;
168 }
169
170 /* the outsize interface routine: accepts sizes, returns a char
171 ** maze. option is a flag for either a sparse or a full maze. Sparse
172 mazes have sizable rooms. option = 3=full, 2=braided, 1=sparse, 0=rooms.*/
173 void
174 maze_gen (Layout maze, int subtype)
175 {
176 xsize = maze->w;
177 ysize = maze->h;
178 ::maze = maze;
179
180 maze->clear ();
181 maze->border ();
182
183 if (xsize < 4 || ysize < 4)
184 return;
185
186 seeds.reset (xsize * ysize);
187
188 if (subtype > 0)
189 push_walls ();
190
191 if (subtype == 0 || subtype == 2)
192 for (int i = (xsize + ysize) / 2; i; --i)
193 push (point (rmg_rndm (1, xsize - 2), rmg_rndm (1, ysize - 2)));
194
195 bool full = subtype == 3;
196
197 /* recursively generate the walls of the maze */
198 /* first pop a random starting point */
199 while (seeds.size)
200 {
201 point p = pop_rand ();
202
203 for (;;)
204 {
205 point pc;
206
207 maze [p.x][p.y] = '#';
208
209 if (find_free_point (pc, p) < 0)
210 break;
211
212 if (full)
213 push (p);
214
215 if (!rmg_rndm (8))
216 {
217 if (!full)
218 push (pc);
219
220 break;
221 }
222
223 p = pc;
224 }
225 }
226
227 seeds.free ();
228 }
229