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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines