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.12 by root, Thu May 8 14:20:19 2008 UTC vs.
Revision 1.27 by root, Sat Apr 23 04:56:52 2011 UTC

1/*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) 1994-2004 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
13 35
14/* we need to maintain a list of wall points to generate 36/* we need to maintain a list of wall points to generate
15 reasonable mazes: a straightforward recursive random walk maze 37 reasonable mazes: a straightforward recursive random walk maze
16 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 */
17 39
40#include <vector>
41
18#include <global.h> 42#include <global.h>
19 43
20#include "random_map.h" 44#include <rmg.h>
21#include "rproto.h" 45#include "rproto.h"
22 46
23/* global variables that everyone needs: don't want to pass them in 47/* global variables that everyone needs: don't want to pass them in
24 as parameters every time. */ 48 as parameters every time. */
25int *wall_x_list = 0; 49static fixed_stack<point> seeds;
26int *wall_y_list = 0; 50static int xsize, ysize;
27int wall_free_size = 0; 51static char **maze;
28 52
29/* heuristically, we need to change wall_chance based on the size of 53static void
30 the maze. */ 54push (point p)
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.*/
37void
38maze_gen (Layout maze, int option)
39{ 55{
40 maze->clear (); 56 seeds.push (p);
41 maze->border (); 57 maze [p.x][p.y] = '#';
58}
42 59
43 /* find how many free wall spots there are */ 60/* randomly returns one of the elements from the wall point list */
44 wall_free_size = 2 * (maze->w - 4) + 2 * (maze->h - 4); 61static point
45 62pop_rand ()
46 make_wall_free_list (maze->w, maze->h); 63{
47 64 return seeds.remove (rmg_rndm (seeds.size));
48 /* return the empty maze */
49 if (wall_free_size <= 0)
50 return;
51
52 /* recursively generate the walls of the maze */
53 /* first pop a random starting point */
54 while (wall_free_size > 0)
55 {
56 int i, j;
57
58 pop_wall_point (&i, &j);
59
60 if (option)
61 fill_maze_full (maze, i, j, maze->w, maze->h);
62 else
63 fill_maze_sparse (maze, i, j, maze->w, maze->h);
64 }
65
66 /* clean up our intermediate data structures. */
67
68 free (wall_x_list);
69 free (wall_y_list);
70} 65}
71 66
72/* the free wall points are those outer points which aren't corners or 67/* the free wall points are those outer points which aren't corners or
73 near corners, and don't have a maze wall growing out of them already. */ 68 near corners, and don't have a maze wall growing out of them already. */
74void 69static void
75make_wall_free_list (int xsize, int ysize) 70push_walls ()
76{ 71{
77 int i, j, count;
78
79 count = 0; /* entries already placed in the free list */
80 /*allocate it */
81 if (wall_free_size < 0)
82 return;
83
84 wall_x_list = (int *)calloc (sizeof (int), wall_free_size);
85 wall_y_list = (int *)calloc (sizeof (int), wall_free_size);
86
87 /* top and bottom wall */ 72 /* top and bottom wall */
88 for (i = 2; i < xsize - 2; i++) 73 for (int x = 2; x < xsize - 2; x++)
89 { 74 {
90 wall_x_list[count] = i; 75 push (point (x, 0));
91 wall_y_list[count] = 0; 76 push (point (x, ysize - 1));
92 count++;
93 wall_x_list[count] = i;
94 wall_y_list[count] = ysize - 1;
95 count++;
96 } 77 }
97 78
98 /* left and right wall */ 79 /* left and right wall */
99 for (j = 2; j < ysize - 2; j++) 80 for (int y = 2; y < ysize - 2; y++)
100 {
101 wall_x_list[count] = 0;
102 wall_y_list[count] = j;
103 count++;
104 wall_x_list[count] = xsize - 1;
105 wall_y_list[count] = j;
106 count++;
107 } 81 {
108} 82 push (point ( 0, y));
109 83 push (point (xsize - 1, y));
110/* randomly returns one of the elements from the wall point list */ 84 }
111void
112pop_wall_point (int *x, int *y)
113{
114 int index = rmg_rndm (wall_free_size);
115
116 *x = wall_x_list[index];
117 *y = wall_y_list[index];
118 /* write the last array point here */
119 wall_x_list[index] = wall_x_list[wall_free_size - 1];
120 wall_y_list[index] = wall_y_list[wall_free_size - 1];
121 wall_free_size--;
122} 85}
123 86
124/* find free point: randomly look for a square adjacent to this one where 87/* find free point: randomly look for a square adjacent to this one where
125we can place a new block without closing a path. We may only look 88we can place a new block without closing a path. We may only look
126up, down, right, or left. */ 89up, down, right, or left. */
127int 90static int
128find_free_point (char **maze, int *x, int *y, int xc, int yc, int xsize, int ysize) 91find_free_point (point &p, point pc)
129{ 92{
130 /* we will randomly pick from this list, 1=up,2=down,3=right,4=left */ 93 /* we will randomly pick from this list, 1=up,2=down,3=right,4=left */
131 int dirlist[4]; 94 int dirlist[4];
132 int count = 0; /* # elements in dirlist */ 95 int count = 0; /* # elements in dirlist */
133 96
97 int xc = pc.x;
98 int yc = pc.y;
99
134 /* look up */ 100 /* look up */
135 if (yc < ysize - 2 && xc > 2 && xc < xsize - 2) /* it is valid to look up */ 101 if (yc < ysize - 2 && xc > 2 && xc < xsize - 2) /* it is valid to look up */
136 { 102 {
137 int cleartest = (int) maze[xc][yc + 1] + (int) maze[xc - 1][yc + 1] + (int) maze[xc + 1][yc + 1]; 103 int cleartest = maze[xc][yc + 1] + maze[xc - 1][yc + 1] + maze[xc + 1][yc + 1]
138
139 cleartest += (int) maze[xc][yc + 2] + (int) maze[xc - 1][yc + 2] + (int) maze[xc + 1][yc + 2]; 104 + maze[xc][yc + 2] + maze[xc - 1][yc + 2] + maze[xc + 1][yc + 2];
140 105
141 if (cleartest == 0) 106 if (cleartest == 0)
142 dirlist[count++] = 1; 107 dirlist[count++] = 1;
143 } 108 }
144 109
145 /* look down */ 110 /* look down */
146 if (yc > 2 && xc > 2 && xc < xsize - 2) /* it is valid to look down */ 111 if (yc > 2 && xc > 2 && xc < xsize - 2) /* it is valid to look down */
147 { 112 {
148 int cleartest = (int) maze[xc][yc - 1] + (int) maze[xc - 1][yc - 1] + (int) maze[xc + 1][yc - 1]; 113 int cleartest = maze[xc][yc - 1] + maze[xc - 1][yc - 1] + maze[xc + 1][yc - 1]
149
150 cleartest += (int) maze[xc][yc - 2] + (int) maze[xc - 1][yc - 2] + (int) maze[xc + 1][yc - 2]; 114 + maze[xc][yc - 2] + maze[xc - 1][yc - 2] + maze[xc + 1][yc - 2];
151 115
152 if (cleartest == 0) 116 if (cleartest == 0)
153 dirlist[count++] = 2; 117 dirlist[count++] = 2;
154 } 118 }
155 119
156 /* look right */ 120 /* look right */
157 if (xc < xsize - 2 && yc > 2 && yc < ysize - 2) /* it is valid to look left */ 121 if (xc < xsize - 2 && yc > 2 && yc < ysize - 2) /* it is valid to look left */
158 { 122 {
159 int cleartest = (int) maze[xc + 1][yc] + (int) maze[xc + 1][yc - 1] + (int) maze[xc + 1][yc + 1]; 123 int cleartest = maze[xc + 1][yc] + maze[xc + 1][yc - 1] + maze[xc + 1][yc + 1]
160
161 cleartest += (int) maze[xc + 2][yc] + (int) maze[xc + 2][yc - 1] + (int) maze[xc + 2][yc + 1]; 124 + maze[xc + 2][yc] + maze[xc + 2][yc - 1] + maze[xc + 2][yc + 1];
162 125
163 if (cleartest == 0) 126 if (cleartest == 0)
164 dirlist[count++] = 3; 127 dirlist[count++] = 3;
165 } 128 }
166 129
167 /* look left */ 130 /* look left */
168 if (xc > 2 && yc > 2 && yc < ysize - 2) /* it is valid to look down */ 131 if (xc > 2 && yc > 2 && yc < ysize - 2) /* it is valid to look down */
169 { 132 {
170 int cleartest = (int) maze[xc - 1][yc] + (int) maze[xc - 1][yc - 1] + (int) maze[xc - 1][yc + 1]; 133 int cleartest = maze[xc - 1][yc] + maze[xc - 1][yc - 1] + maze[xc - 1][yc + 1]
171
172 cleartest += (int) maze[xc - 2][yc] + (int) maze[xc - 2][yc - 1] + (int) maze[xc - 2][yc + 1]; 134 + maze[xc - 2][yc] + maze[xc - 2][yc - 1] + maze[xc - 2][yc + 1];
173 135
174 if (cleartest == 0) 136 if (cleartest == 0)
175 dirlist[count++] = 4; 137 dirlist[count++] = 4;
176 } 138 }
177 139
180 142
181 /* choose a random direction */ 143 /* choose a random direction */
182 switch (dirlist [rmg_rndm (count)]) 144 switch (dirlist [rmg_rndm (count)])
183 { 145 {
184 case 1: /* up */ 146 case 1: /* up */
147 p.x = xc;
185 *y = yc + 1; 148 p.y = yc + 1;
186 *x = xc;
187 break; 149 break;
188 150
189 case 2: /* down */ 151 case 2: /* down */
152 p.x = xc;
190 *y = yc - 1; 153 p.y = yc - 1;
191 *x = xc;
192 break; 154 break;
193 155
194 case 3: /* right */ 156 case 3: /* right */
195 *y = yc;
196 *x = xc + 1; 157 p.x = xc + 1;
158 p.y = yc;
197 break; 159 break;
198 160
199 case 4: /* left */ 161 case 4: /* left */
200 *x = xc - 1; 162 p.x = xc - 1;
201 *y = yc; 163 p.y = yc;
202 break; 164 break;
203
204 default: /* ??? */
205 return -1;
206
207 } 165 }
208 166
209 return 1; 167 return 1;
210} 168}
211 169
212/* recursive routine which will fill every available space in the maze 170/* the outsize interface routine: accepts sizes, returns a char
213 with walls*/ 171** maze. option is a flag for either a sparse or a full maze. Sparse
172mazes have sizable rooms. option = 3=full, 2=braided, 1=sparse, 0=rooms.*/
214void 173void
215fill_maze_full (char **maze, int x, int y, int xsize, int ysize) 174maze_gen (layout &maze, int subtype)
216{ 175{
217 int xc, yc; 176 xsize = maze.w;
177 ysize = maze.h;
178 ::maze = maze;
218 179
219 /* write a wall here */ 180 maze.clear ();
220 maze[x][y] = '#'; 181 maze.border ();
221 182
222 /* decide if we're going to pick from the wall_free_list */ 183 if (xsize < 4 || ysize < 4)
223 if (rmg_rndm (4) && wall_free_size > 0) 184 return;
224 { 185
225 pop_wall_point (&xc, &yc); 186 seeds.reset (xsize * ysize);
226 fill_maze_full (maze, xc, yc, 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)
227 } 200 {
201 point p = pop_rand ();
228 202
229 /* change the if to a while for a complete maze. */ 203 for (;;)
230 while (find_free_point (maze, &xc, &yc, x, y, xsize, ysize) != -1) 204 {
231 fill_maze_full (maze, xc, yc, xsize, ysize); 205 point pc;
232}
233 206
234/* recursive routine which will fill much of the maze, but will leave 207 maze [p.x][p.y] = '#';
235 some free spots (possibly large) toward the center.*/
236void
237fill_maze_sparse (char **maze, int x, int y, int xsize, int ysize)
238{
239 int xc, yc;
240 208
241 /* write a wall here */ 209 if (find_free_point (pc, p) < 0)
242 maze[x][y] = '#'; 210 break;
243 211
244 /* decide if we're going to pick from the wall_free_list */ 212 if (full)
245 if (rmg_rndm (4) && wall_free_size > 0) 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 }
246 { 225 }
247 pop_wall_point (&xc, &yc);
248 fill_maze_sparse (maze, xc, yc, xsize, ysize);
249 }
250 226
251 /* change the if to a while for a complete maze. */ 227 seeds.free ();
252 if (find_free_point (maze, &xc, &yc, x, y, xsize, ysize) != -1)
253 fill_maze_sparse (maze, xc, yc, xsize, ysize);
254} 228}
255 229

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines