ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/maze_gen.C
(Generate patch)

Comparing deliantra/server/random_maps/maze_gen.C (file contents):
Revision 1.8 by root, Fri Apr 11 21:09:53 2008 UTC vs.
Revision 1.19 by root, Sun Jun 27 16:36:12 2010 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines