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.16 by root, Sat Nov 7 18:32:45 2009 UTC vs.
Revision 1.30 by root, Wed Nov 16 23:42:02 2016 UTC

1/* 1/*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG. 2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 * 3 *
4 * Copyright (©) 2005,2006,2007,2008,2009 Marc Alexander Lehmann / Robin Redeker / the Deliantra team 4 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) Crossfire Development Team (restored, original file without copyright notice) 5 * Copyright (©) 1994-2004 Crossfire Development Team (restored, original file without copyright notice)
6 * 6 *
7 * Deliantra is free software: you can redistribute it and/or modify it under 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 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 9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version. 10 * option) any later version.
11 * 11 *
12 * This program is distributed in the hope that it will be useful, 12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details. 15 * GNU General Public License for more details.
16 * 16 *
17 * You should have received a copy of the Affero GNU General Public License 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 18 * and the GNU General Public License along with this program. If not, see
19 * <http://www.gnu.org/licenses/>. 19 * <http://www.gnu.org/licenses/>.
20 * 20 *
21 * The authors can be reached via e-mail to <support@deliantra.net> 21 * The authors can be reached via e-mail to <support@deliantra.net>
22 */ 22 */
23 23
24/* peterm@langmuir.eecs.berkeley.edu: this function generates a random 24/* peterm@langmuir.eecs.berkeley.edu: this function generates a random
25blocked 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
35 35
36/* we need to maintain a list of wall points to generate 36/* we need to maintain a list of wall points to generate
37 reasonable mazes: a straightforward recursive random walk maze 37 reasonable mazes: a straightforward recursive random walk maze
38 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 */
39 39
40#include <vector>
41
40#include <global.h> 42#include <global.h>
41 43
42#include "random_map.h" 44#include <rmg.h>
43#include "rproto.h" 45#include "rproto.h"
44 46
45/* 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
46 as parameters every time. */ 48 as parameters every time. */
47static int *wall_x_list = 0; 49static fixed_stack<point> seeds;
48static int *wall_y_list = 0; 50static int xsize, ysize;
49static int wall_free_size = 0; 51static char **maze;
52
53static void
54push (point p)
55{
56 seeds.push (p);
57 maze [p.x][p.y] = '#';
58}
59
60/* randomly returns one of the elements from the wall point list */
61static point
62pop_rand ()
63{
64 return seeds.remove (rmg_rndm (seeds.size));
65}
50 66
51/* 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
52 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. */
53static void 69static void
54make_wall_free_list (int xsize, int ysize) 70push_walls ()
55{ 71{
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 */ 72 /* top and bottom wall */
67 for (i = 2; i < xsize - 2; i++) 73 for (int x = 2; x < xsize - 2; x++)
68 { 74 {
69 wall_x_list[count] = i; 75 push (point (x, 0));
70 wall_y_list[count] = 0; 76 push (point (x, ysize - 1));
71 count++;
72 wall_x_list[count] = i;
73 wall_y_list[count] = ysize - 1;
74 count++;
75 } 77 }
76 78
77 /* left and right wall */ 79 /* left and right wall */
78 for (j = 2; j < ysize - 2; j++) 80 for (int y = 2; y < ysize - 2; y++)
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 } 81 {
87} 82 push (point ( 0, y));
88 83 push (point (xsize - 1, y));
89/* randomly returns one of the elements from the wall point list */ 84 }
90static void
91pop_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} 85}
102 86
103/* 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
104we 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
105up, down, right, or left. */ 89up, down, right, or left. */
106static int 90static int
107find_free_point (char **maze, int *x, int *y, int xc, int yc, int xsize, int ysize) 91find_free_point (point &p, point pc)
108{ 92{
109 /* 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 */
110 int dirlist[4]; 94 int dirlist[4];
111 int count = 0; /* # elements in dirlist */ 95 int count = 0; /* # elements in dirlist */
112 96
97 int xc = pc.x;
98 int yc = pc.y;
99
113 /* look up */ 100 /* look up */
114 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 */
115 { 102 {
116 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]
117
118 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];
119 105
120 if (cleartest == 0) 106 if (cleartest == 0)
121 dirlist[count++] = 1; 107 dirlist[count++] = 1;
122 } 108 }
123 109
124 /* look down */ 110 /* look down */
125 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 */
126 { 112 {
127 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]
128
129 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];
130 115
131 if (cleartest == 0) 116 if (cleartest == 0)
132 dirlist[count++] = 2; 117 dirlist[count++] = 2;
133 } 118 }
134 119
135 /* look right */ 120 /* look right */
136 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 */
137 { 122 {
138 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]
139
140 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];
141 125
142 if (cleartest == 0) 126 if (cleartest == 0)
143 dirlist[count++] = 3; 127 dirlist[count++] = 3;
144 } 128 }
145 129
146 /* look left */ 130 /* look left */
147 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 */
148 { 132 {
149 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]
150
151 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];
152 135
153 if (cleartest == 0) 136 if (cleartest == 0)
154 dirlist[count++] = 4; 137 dirlist[count++] = 4;
155 } 138 }
156 139
159 142
160 /* choose a random direction */ 143 /* choose a random direction */
161 switch (dirlist [rmg_rndm (count)]) 144 switch (dirlist [rmg_rndm (count)])
162 { 145 {
163 case 1: /* up */ 146 case 1: /* up */
147 p.x = xc;
164 *y = yc + 1; 148 p.y = yc + 1;
165 *x = xc;
166 break; 149 break;
167 150
168 case 2: /* down */ 151 case 2: /* down */
152 p.x = xc;
169 *y = yc - 1; 153 p.y = yc - 1;
170 *x = xc;
171 break; 154 break;
172 155
173 case 3: /* right */ 156 case 3: /* right */
174 *y = yc;
175 *x = xc + 1; 157 p.x = xc + 1;
158 p.y = yc;
176 break; 159 break;
177 160
178 case 4: /* left */ 161 case 4: /* left */
179 *x = xc - 1; 162 p.x = xc - 1;
180 *y = yc; 163 p.y = yc;
181 break; 164 break;
182
183 default: /* ??? */
184 return -1;
185
186 } 165 }
187 166
188 return 1; 167 return 1;
189}
190
191/* recursive routine which will fill every available space in the maze
192 with walls*/
193static void
194fill_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.*/
215static void
216fill_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} 168}
234 169
235/* the outsize interface routine: accepts sizes, returns a char 170/* the outsize interface routine: accepts sizes, returns a char
236** maze. option is a flag for either a sparse or a full maze. Sparse 171** maze. option is a flag for either a sparse or a full maze. Sparse
237mazes have sizable rooms. option = 1, full, 0, sparse.*/ 172mazes have sizable rooms. option = 3=full, 2=braided, 1=sparse, 0=rooms.*/
238void 173void
239maze_gen (Layout maze, int option) 174maze_gen (layout &maze, int subtype)
240{ 175{
176 xsize = maze.w;
177 ysize = maze.h;
178 ::maze = maze;
179
241 maze->clear (); 180 maze.clear ();
242 maze->border (); 181 maze.border ();
243 182
244 /* find how many free wall spots there are */ 183 if (xsize < 4 || ysize < 4)
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; 184 return;
185
186 seeds.reset (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;
252 196
253 /* recursively generate the walls of the maze */ 197 /* recursively generate the walls of the maze */
254 /* first pop a random starting point */ 198 /* first pop a random starting point */
255 while (wall_free_size > 0) 199 while (seeds.size)
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 } 200 {
201 point p = pop_rand ();
266 202
267 /* clean up our intermediate data structures. */ 203 for (;;)
204 {
205 point pc;
268 206
269 free (wall_x_list); 207 maze [p.x][p.y] = '#';
270 free (wall_y_list);
271}
272 208
209 if (find_free_point (pc, p) < 0)
210 break;
211
212 if (full)
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 }
225 }
226
227 seeds.free ();
228}
229

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines