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.14 by root, Fri Nov 6 13:03:34 2009 UTC vs.
Revision 1.23 by root, Wed Jun 30 20:51:02 2010 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 */
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 "random_map.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. */
25static int *wall_x_list = 0; 49static fixed_stack<point> seeds;
26static int *wall_y_list = 0; 50static int xsize, ysize;
27static int 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)
55{
56 seeds.push (p);
57 maze [p.x][p.y] = '#';
58}
31 59
32static int wall_chance; 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}
33 66
34/* 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
35 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. */
36static void 69static void
37make_wall_free_list (int xsize, int ysize) 70push_walls ()
38{ 71{
39 int i, j, count;
40
41 count = 0; /* entries already placed in the free list */
42 /*allocate it */
43 if (wall_free_size < 0)
44 return;
45
46 wall_x_list = (int *)calloc (sizeof (int), wall_free_size);
47 wall_y_list = (int *)calloc (sizeof (int), wall_free_size);
48
49 /* top and bottom wall */ 72 /* top and bottom wall */
50 for (i = 2; i < xsize - 2; i++) 73 for (int x = 2; x < xsize - 2; x++)
51 { 74 {
52 wall_x_list[count] = i; 75 push (point (x, 0));
53 wall_y_list[count] = 0; 76 push (point (x, ysize - 1));
54 count++;
55 wall_x_list[count] = i;
56 wall_y_list[count] = ysize - 1;
57 count++;
58 } 77 }
59 78
60 /* left and right wall */ 79 /* left and right wall */
61 for (j = 2; j < ysize - 2; j++) 80 for (int y = 2; y < ysize - 2; y++)
62 {
63 wall_x_list[count] = 0;
64 wall_y_list[count] = j;
65 count++;
66 wall_x_list[count] = xsize - 1;
67 wall_y_list[count] = j;
68 count++;
69 } 81 {
70} 82 push (point ( 0, y));
71 83 push (point (xsize - 1, y));
72/* randomly returns one of the elements from the wall point list */ 84 }
73static void
74pop_wall_point (int *x, int *y)
75{
76 int index = rmg_rndm (wall_free_size);
77
78 *x = wall_x_list[index];
79 *y = wall_y_list[index];
80 /* write the last array point here */
81 wall_x_list[index] = wall_x_list[wall_free_size - 1];
82 wall_y_list[index] = wall_y_list[wall_free_size - 1];
83 wall_free_size--;
84} 85}
85 86
86/* 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
87we 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
88up, down, right, or left. */ 89up, down, right, or left. */
89static int 90static int
90find_free_point (char **maze, int *x, int *y, int xc, int yc, int xsize, int ysize) 91find_free_point (point &p, point pc)
91{ 92{
92 /* 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 */
93 int dirlist[4]; 94 int dirlist[4];
94 int count = 0; /* # elements in dirlist */ 95 int count = 0; /* # elements in dirlist */
95 96
97 int xc = pc.x;
98 int yc = pc.y;
99
96 /* look up */ 100 /* look up */
97 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 */
98 { 102 {
99 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]
100
101 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];
102 105
103 if (cleartest == 0) 106 if (cleartest == 0)
104 dirlist[count++] = 1; 107 dirlist[count++] = 1;
105 } 108 }
106 109
107 /* look down */ 110 /* look down */
108 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 */
109 { 112 {
110 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]
111
112 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];
113 115
114 if (cleartest == 0) 116 if (cleartest == 0)
115 dirlist[count++] = 2; 117 dirlist[count++] = 2;
116 } 118 }
117 119
118 /* look right */ 120 /* look right */
119 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 */
120 { 122 {
121 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]
122
123 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];
124 125
125 if (cleartest == 0) 126 if (cleartest == 0)
126 dirlist[count++] = 3; 127 dirlist[count++] = 3;
127 } 128 }
128 129
129 /* look left */ 130 /* look left */
130 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 */
131 { 132 {
132 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]
133
134 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];
135 135
136 if (cleartest == 0) 136 if (cleartest == 0)
137 dirlist[count++] = 4; 137 dirlist[count++] = 4;
138 } 138 }
139 139
142 142
143 /* choose a random direction */ 143 /* choose a random direction */
144 switch (dirlist [rmg_rndm (count)]) 144 switch (dirlist [rmg_rndm (count)])
145 { 145 {
146 case 1: /* up */ 146 case 1: /* up */
147 p.x = xc;
147 *y = yc + 1; 148 p.y = yc + 1;
148 *x = xc;
149 break; 149 break;
150 150
151 case 2: /* down */ 151 case 2: /* down */
152 p.x = xc;
152 *y = yc - 1; 153 p.y = yc - 1;
153 *x = xc;
154 break; 154 break;
155 155
156 case 3: /* right */ 156 case 3: /* right */
157 *y = yc;
158 *x = xc + 1; 157 p.x = xc + 1;
158 p.y = yc;
159 break; 159 break;
160 160
161 case 4: /* left */ 161 case 4: /* left */
162 *x = xc - 1; 162 p.x = xc - 1;
163 *y = yc; 163 p.y = yc;
164 break; 164 break;
165
166 default: /* ??? */
167 return -1;
168
169 } 165 }
170 166
171 return 1; 167 return 1;
172}
173
174/* recursive routine which will fill every available space in the maze
175 with walls*/
176static void
177fill_maze_full (char **maze, int x, int y, int xsize, int ysize)
178{
179 int xc, yc;
180
181 /* write a wall here */
182 maze[x][y] = '#';
183
184 /* decide if we're going to pick from the wall_free_list */
185 if (rmg_rndm (4) && wall_free_size > 0)
186 {
187 pop_wall_point (&xc, &yc);
188 fill_maze_full (maze, xc, yc, xsize, ysize);
189 }
190
191 /* change the if to a while for a complete maze. */
192 while (find_free_point (maze, &xc, &yc, x, y, xsize, ysize) != -1)
193 fill_maze_full (maze, xc, yc, xsize, ysize);
194}
195
196/* recursive routine which will fill much of the maze, but will leave
197 some free spots (possibly large) toward the center.*/
198static void
199fill_maze_sparse (char **maze, int x, int y, int xsize, int ysize)
200{
201 int xc, yc;
202
203 /* write a wall here */
204 maze[x][y] = '#';
205
206 /* decide if we're going to pick from the wall_free_list */
207 if (rmg_rndm (4) && wall_free_size > 0)
208 {
209 pop_wall_point (&xc, &yc);
210 fill_maze_sparse (maze, xc, yc, xsize, ysize);
211 }
212
213 /* change the if to a while for a complete maze. */
214 if (find_free_point (maze, &xc, &yc, x, y, xsize, ysize) != -1)
215 fill_maze_sparse (maze, xc, yc, xsize, ysize);
216} 168}
217 169
218/* the outsize interface routine: accepts sizes, returns a char 170/* the outsize interface routine: accepts sizes, returns a char
219** 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
220mazes have sizable rooms. option = 1, full, 0, sparse.*/ 172mazes have sizable rooms. option = 3=full, 2=braided, 1=sparse, 0=rooms.*/
221void 173void
222maze_gen (Layout maze, int option) 174maze_gen (Layout maze, int subtype)
223{ 175{
176 xsize = maze->w;
177 ysize = maze->h;
178 ::maze = maze;
179
224 maze->clear (); 180 maze->clear ();
225 maze->border (); 181 maze->border ();
226 182
227 /* find how many free wall spots there are */ 183 if (xsize < 4 || ysize < 4)
228 wall_free_size = 2 * (maze->w - 4) + 2 * (maze->h - 4);
229
230 make_wall_free_list (maze->w, maze->h);
231
232 /* return the empty maze */
233 if (wall_free_size <= 0)
234 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;
235 196
236 /* recursively generate the walls of the maze */ 197 /* recursively generate the walls of the maze */
237 /* first pop a random starting point */ 198 /* first pop a random starting point */
238 while (wall_free_size > 0) 199 while (seeds.size)
239 {
240 int i, j;
241
242 pop_wall_point (&i, &j);
243
244 if (option)
245 fill_maze_full (maze, i, j, maze->w, maze->h);
246 else
247 fill_maze_sparse (maze, i, j, maze->w, maze->h);
248 } 200 {
201 point p = pop_rand ();
249 202
250 /* clean up our intermediate data structures. */ 203 for (;;)
204 {
205 point pc;
251 206
252 free (wall_x_list); 207 maze [p.x][p.y] = '#';
253 free (wall_y_list);
254}
255 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