ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/maze_gen.C
Revision: 1.16
Committed: Sat Nov 7 18:32:45 2009 UTC (14 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-3_0, rel-2_92, rel-2_93
Changes since 1.15: +22 -0 lines
Log Message:
add copyright notices to .C files

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 <global.h>
41
42 #include "random_map.h"
43 #include "rproto.h"
44
45 /* global variables that everyone needs: don't want to pass them in
46 as parameters every time. */
47 static int *wall_x_list = 0;
48 static int *wall_y_list = 0;
49 static int wall_free_size = 0;
50
51 /* the free wall points are those outer points which aren't corners or
52 near corners, and don't have a maze wall growing out of them already. */
53 static void
54 make_wall_free_list (int xsize, int ysize)
55 {
56 int i, j, count;
57
58 count = 0; /* entries already placed in the free list */
59 /*allocate it */
60 if (wall_free_size < 0)
61 return;
62
63 wall_x_list = (int *)calloc (sizeof (int), wall_free_size);
64 wall_y_list = (int *)calloc (sizeof (int), wall_free_size);
65
66 /* top and bottom wall */
67 for (i = 2; i < xsize - 2; i++)
68 {
69 wall_x_list[count] = i;
70 wall_y_list[count] = 0;
71 count++;
72 wall_x_list[count] = i;
73 wall_y_list[count] = ysize - 1;
74 count++;
75 }
76
77 /* left and right wall */
78 for (j = 2; j < ysize - 2; j++)
79 {
80 wall_x_list[count] = 0;
81 wall_y_list[count] = j;
82 count++;
83 wall_x_list[count] = xsize - 1;
84 wall_y_list[count] = j;
85 count++;
86 }
87 }
88
89 /* randomly returns one of the elements from the wall point list */
90 static void
91 pop_wall_point (int *x, int *y)
92 {
93 int index = rmg_rndm (wall_free_size);
94
95 *x = wall_x_list[index];
96 *y = wall_y_list[index];
97 /* write the last array point here */
98 wall_x_list[index] = wall_x_list[wall_free_size - 1];
99 wall_y_list[index] = wall_y_list[wall_free_size - 1];
100 wall_free_size--;
101 }
102
103 /* find free point: randomly look for a square adjacent to this one where
104 we can place a new block without closing a path. We may only look
105 up, down, right, or left. */
106 static int
107 find_free_point (char **maze, int *x, int *y, int xc, int yc, int xsize, int ysize)
108 {
109 /* we will randomly pick from this list, 1=up,2=down,3=right,4=left */
110 int dirlist[4];
111 int count = 0; /* # elements in dirlist */
112
113 /* look up */
114 if (yc < ysize - 2 && xc > 2 && xc < xsize - 2) /* it is valid to look up */
115 {
116 int cleartest = (int) maze[xc][yc + 1] + (int) maze[xc - 1][yc + 1] + (int) maze[xc + 1][yc + 1];
117
118 cleartest += (int) maze[xc][yc + 2] + (int) maze[xc - 1][yc + 2] + (int) maze[xc + 1][yc + 2];
119
120 if (cleartest == 0)
121 dirlist[count++] = 1;
122 }
123
124 /* look down */
125 if (yc > 2 && xc > 2 && xc < xsize - 2) /* it is valid to look down */
126 {
127 int cleartest = (int) maze[xc][yc - 1] + (int) maze[xc - 1][yc - 1] + (int) maze[xc + 1][yc - 1];
128
129 cleartest += (int) maze[xc][yc - 2] + (int) maze[xc - 1][yc - 2] + (int) maze[xc + 1][yc - 2];
130
131 if (cleartest == 0)
132 dirlist[count++] = 2;
133 }
134
135 /* look right */
136 if (xc < xsize - 2 && yc > 2 && yc < ysize - 2) /* it is valid to look left */
137 {
138 int cleartest = (int) maze[xc + 1][yc] + (int) maze[xc + 1][yc - 1] + (int) maze[xc + 1][yc + 1];
139
140 cleartest += (int) maze[xc + 2][yc] + (int) maze[xc + 2][yc - 1] + (int) maze[xc + 2][yc + 1];
141
142 if (cleartest == 0)
143 dirlist[count++] = 3;
144 }
145
146 /* look left */
147 if (xc > 2 && yc > 2 && yc < ysize - 2) /* it is valid to look down */
148 {
149 int cleartest = (int) maze[xc - 1][yc] + (int) maze[xc - 1][yc - 1] + (int) maze[xc - 1][yc + 1];
150
151 cleartest += (int) maze[xc - 2][yc] + (int) maze[xc - 2][yc - 1] + (int) maze[xc - 2][yc + 1];
152
153 if (cleartest == 0)
154 dirlist[count++] = 4;
155 }
156
157 if (count == 0)
158 return -1; /* failed to find any clear points */
159
160 /* choose a random direction */
161 switch (dirlist [rmg_rndm (count)])
162 {
163 case 1: /* up */
164 *y = yc + 1;
165 *x = xc;
166 break;
167
168 case 2: /* down */
169 *y = yc - 1;
170 *x = xc;
171 break;
172
173 case 3: /* right */
174 *y = yc;
175 *x = xc + 1;
176 break;
177
178 case 4: /* left */
179 *x = xc - 1;
180 *y = yc;
181 break;
182
183 default: /* ??? */
184 return -1;
185
186 }
187
188 return 1;
189 }
190
191 /* recursive routine which will fill every available space in the maze
192 with walls*/
193 static void
194 fill_maze_full (char **maze, int x, int y, int xsize, int ysize)
195 {
196 int xc, yc;
197
198 /* write a wall here */
199 maze[x][y] = '#';
200
201 /* decide if we're going to pick from the wall_free_list */
202 if (rmg_rndm (4) && wall_free_size > 0)
203 {
204 pop_wall_point (&xc, &yc);
205 fill_maze_full (maze, xc, yc, xsize, ysize);
206 }
207
208 /* change the if to a while for a complete maze. */
209 while (find_free_point (maze, &xc, &yc, x, y, xsize, ysize) != -1)
210 fill_maze_full (maze, xc, yc, xsize, ysize);
211 }
212
213 /* recursive routine which will fill much of the maze, but will leave
214 some free spots (possibly large) toward the center.*/
215 static void
216 fill_maze_sparse (char **maze, int x, int y, int xsize, int ysize)
217 {
218 int xc, yc;
219
220 /* write a wall here */
221 maze[x][y] = '#';
222
223 /* decide if we're going to pick from the wall_free_list */
224 if (rmg_rndm (4) && wall_free_size > 0)
225 {
226 pop_wall_point (&xc, &yc);
227 fill_maze_sparse (maze, xc, yc, xsize, ysize);
228 }
229
230 /* change the if to a while for a complete maze. */
231 if (find_free_point (maze, &xc, &yc, x, y, xsize, ysize) != -1)
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
237 mazes have sizable rooms. option = 1, full, 0, sparse.*/
238 void
239 maze_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)
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);
271 }
272