ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/maze_gen.C
Revision: 1.31
Committed: Sat Nov 17 23:40:02 2018 UTC (5 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.30: +1 -0 lines
Log Message:
copyright update 2018

File Contents

# Content
1 /*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team
5 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
6 * Copyright (©) 1994-2004 Crossfire Development Team (restored, original file without copyright notice)
7 *
8 * Deliantra is free software: you can redistribute it and/or modify it under
9 * the terms of the Affero GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the Affero GNU General Public License
19 * and the GNU General Public License along with this program. If not, see
20 * <http://www.gnu.org/licenses/>.
21 *
22 * The authors can be reached via e-mail to <support@deliantra.net>
23 */
24
25 /* peterm@langmuir.eecs.berkeley.edu: this function generates a random
26 blocked maze with the property that there is only one path from one spot
27 to any other, and there is always a path from one spot to any other.
28
29 input: xsize, ysize;
30 output: a char** array with # and . for closed and open respectively.
31
32 a char value of 0 represents a blank space: a '#' is
33 a wall.
34
35 */
36
37 /* we need to maintain a list of wall points to generate
38 reasonable mazes: a straightforward recursive random walk maze
39 generator would generate a map with a trivial circle-the-outer-wall solution */
40
41 #include <vector>
42
43 #include <global.h>
44
45 #include <rmg.h>
46 #include "rproto.h"
47
48 /* global variables that everyone needs: don't want to pass them in
49 as parameters every time. */
50 static fixed_stack<point> seeds;
51 static int xsize, ysize;
52 static char **maze;
53
54 static void
55 push (point p)
56 {
57 seeds.push (p);
58 maze [p.x][p.y] = '#';
59 }
60
61 /* randomly returns one of the elements from the wall point list */
62 static point
63 pop_rand ()
64 {
65 return seeds.remove (rmg_rndm (seeds.size));
66 }
67
68 /* the free wall points are those outer points which aren't corners or
69 near corners, and don't have a maze wall growing out of them already. */
70 static void
71 push_walls ()
72 {
73 /* top and bottom wall */
74 for (int x = 2; x < xsize - 2; x++)
75 {
76 push (point (x, 0));
77 push (point (x, ysize - 1));
78 }
79
80 /* left and right wall */
81 for (int y = 2; y < ysize - 2; y++)
82 {
83 push (point ( 0, y));
84 push (point (xsize - 1, y));
85 }
86 }
87
88 /* find free point: randomly look for a square adjacent to this one where
89 we can place a new block without closing a path. We may only look
90 up, down, right, or left. */
91 static int
92 find_free_point (point &p, point pc)
93 {
94 /* we will randomly pick from this list, 1=up,2=down,3=right,4=left */
95 int dirlist[4];
96 int count = 0; /* # elements in dirlist */
97
98 int xc = pc.x;
99 int yc = pc.y;
100
101 /* look up */
102 if (yc < ysize - 2 && xc > 2 && xc < xsize - 2) /* it is valid to look up */
103 {
104 int cleartest = maze[xc][yc + 1] + maze[xc - 1][yc + 1] + maze[xc + 1][yc + 1]
105 + maze[xc][yc + 2] + maze[xc - 1][yc + 2] + maze[xc + 1][yc + 2];
106
107 if (cleartest == 0)
108 dirlist[count++] = 1;
109 }
110
111 /* look down */
112 if (yc > 2 && xc > 2 && xc < xsize - 2) /* it is valid to look down */
113 {
114 int cleartest = maze[xc][yc - 1] + maze[xc - 1][yc - 1] + maze[xc + 1][yc - 1]
115 + maze[xc][yc - 2] + maze[xc - 1][yc - 2] + maze[xc + 1][yc - 2];
116
117 if (cleartest == 0)
118 dirlist[count++] = 2;
119 }
120
121 /* look right */
122 if (xc < xsize - 2 && yc > 2 && yc < ysize - 2) /* it is valid to look left */
123 {
124 int cleartest = maze[xc + 1][yc] + maze[xc + 1][yc - 1] + maze[xc + 1][yc + 1]
125 + maze[xc + 2][yc] + maze[xc + 2][yc - 1] + maze[xc + 2][yc + 1];
126
127 if (cleartest == 0)
128 dirlist[count++] = 3;
129 }
130
131 /* look left */
132 if (xc > 2 && yc > 2 && yc < ysize - 2) /* it is valid to look down */
133 {
134 int cleartest = maze[xc - 1][yc] + maze[xc - 1][yc - 1] + maze[xc - 1][yc + 1]
135 + maze[xc - 2][yc] + maze[xc - 2][yc - 1] + maze[xc - 2][yc + 1];
136
137 if (cleartest == 0)
138 dirlist[count++] = 4;
139 }
140
141 if (count == 0)
142 return -1; /* failed to find any clear points */
143
144 /* choose a random direction */
145 switch (dirlist [rmg_rndm (count)])
146 {
147 case 1: /* up */
148 p.x = xc;
149 p.y = yc + 1;
150 break;
151
152 case 2: /* down */
153 p.x = xc;
154 p.y = yc - 1;
155 break;
156
157 case 3: /* right */
158 p.x = xc + 1;
159 p.y = yc;
160 break;
161
162 case 4: /* left */
163 p.x = xc - 1;
164 p.y = yc;
165 break;
166 }
167
168 return 1;
169 }
170
171 /* the outsize interface routine: accepts sizes, returns a char
172 ** maze. option is a flag for either a sparse or a full maze. Sparse
173 mazes have sizable rooms. option = 3=full, 2=braided, 1=sparse, 0=rooms.*/
174 void
175 maze_gen (layout &maze, int subtype)
176 {
177 xsize = maze.w;
178 ysize = maze.h;
179 ::maze = maze;
180
181 maze.clear ();
182 maze.border ();
183
184 if (xsize < 4 || ysize < 4)
185 return;
186
187 seeds.reset (xsize * ysize);
188
189 if (subtype > 0)
190 push_walls ();
191
192 if (subtype == 0 || subtype == 2)
193 for (int i = (xsize + ysize) / 2; i; --i)
194 push (point (rmg_rndm (1, xsize - 2), rmg_rndm (1, ysize - 2)));
195
196 bool full = subtype == 3;
197
198 /* recursively generate the walls of the maze */
199 /* first pop a random starting point */
200 while (seeds.size)
201 {
202 point p = pop_rand ();
203
204 for (;;)
205 {
206 point pc;
207
208 maze [p.x][p.y] = '#';
209
210 if (find_free_point (pc, p) < 0)
211 break;
212
213 if (full)
214 push (p);
215
216 if (!rmg_rndm (8))
217 {
218 if (!full)
219 push (pc);
220
221 break;
222 }
223
224 p = pc;
225 }
226 }
227
228 seeds.free ();
229 }
230