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.3 by root, Sun Sep 10 16:06:37 2006 UTC vs.
Revision 1.17 by root, Sat Jun 26 23:53:31 2010 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines