ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/maze_gen.C
Revision: 1.28
Committed: Tue Jan 3 11:25:34 2012 UTC (12 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.27: +1 -1 lines
Log Message:
update copyrights to 2012

File Contents

# User Rev Content
1 root 1.16 /*
2     * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3     *
4 root 1.28 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 root 1.27 * Copyright (©) 1994-2004 Crossfire Development Team (restored, original file without copyright notice)
6 root 1.16 *
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 root 1.5
24 elmex 1.1 /* 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 root 1.20 #include <vector>
41    
42 elmex 1.1 #include <global.h>
43 root 1.3
44 root 1.26 #include <rmg.h>
45 root 1.8 #include "rproto.h"
46 elmex 1.1
47     /* global variables that everyone needs: don't want to pass them in
48     as parameters every time. */
49 root 1.23 static fixed_stack<point> seeds;
50 root 1.19 static int xsize, ysize;
51 root 1.20 static char **maze;
52 elmex 1.1
53 root 1.21 static void
54     push (point p)
55     {
56 root 1.23 seeds.push (p);
57     maze [p.x][p.y] = '#';
58     }
59 root 1.21
60 root 1.23 /* randomly returns one of the elements from the wall point list */
61     static point
62     pop_rand ()
63     {
64     return seeds.remove (rmg_rndm (seeds.size));
65 root 1.21 }
66    
67 elmex 1.1 /* the free wall points are those outer points which aren't corners or
68     near corners, and don't have a maze wall growing out of them already. */
69 root 1.14 static void
70 root 1.21 push_walls ()
71 root 1.3 {
72 elmex 1.1 /* top and bottom wall */
73 root 1.20 for (int x = 2; x < xsize - 2; x++)
74 root 1.3 {
75 root 1.21 push (point (x, 0));
76     push (point (x, ysize - 1));
77 root 1.3 }
78 elmex 1.1
79     /* left and right wall */
80 root 1.20 for (int y = 2; y < ysize - 2; y++)
81 root 1.3 {
82 root 1.21 push (point ( 0, y));
83     push (point (xsize - 1, y));
84 root 1.3 }
85 elmex 1.1 }
86    
87     /* find free point: randomly look for a square adjacent to this one where
88     we can place a new block without closing a path. We may only look
89     up, down, right, or left. */
90 root 1.14 static int
91 root 1.20 find_free_point (point &p, point pc)
92 root 1.3 {
93 root 1.12 /* we will randomly pick from this list, 1=up,2=down,3=right,4=left */
94 root 1.3 int dirlist[4];
95     int count = 0; /* # elements in dirlist */
96 elmex 1.1
97 root 1.20 int xc = pc.x;
98     int yc = pc.y;
99    
100 elmex 1.1 /* look up */
101 root 1.3 if (yc < ysize - 2 && xc > 2 && xc < xsize - 2) /* it is valid to look up */
102 elmex 1.1 {
103 root 1.17 int cleartest = maze[xc][yc + 1] + maze[xc - 1][yc + 1] + maze[xc + 1][yc + 1]
104     + maze[xc][yc + 2] + maze[xc - 1][yc + 2] + maze[xc + 1][yc + 2];
105 root 1.3
106     if (cleartest == 0)
107 root 1.12 dirlist[count++] = 1;
108 elmex 1.1 }
109    
110     /* look down */
111 root 1.3 if (yc > 2 && xc > 2 && xc < xsize - 2) /* it is valid to look down */
112 elmex 1.1 {
113 root 1.17 int cleartest = maze[xc][yc - 1] + maze[xc - 1][yc - 1] + maze[xc + 1][yc - 1]
114     + maze[xc][yc - 2] + maze[xc - 1][yc - 2] + maze[xc + 1][yc - 2];
115 root 1.3
116     if (cleartest == 0)
117 root 1.12 dirlist[count++] = 2;
118 elmex 1.1 }
119    
120     /* look right */
121 root 1.3 if (xc < xsize - 2 && yc > 2 && yc < ysize - 2) /* it is valid to look left */
122 elmex 1.1 {
123 root 1.17 int cleartest = maze[xc + 1][yc] + maze[xc + 1][yc - 1] + maze[xc + 1][yc + 1]
124     + maze[xc + 2][yc] + maze[xc + 2][yc - 1] + maze[xc + 2][yc + 1];
125 root 1.3
126     if (cleartest == 0)
127 root 1.12 dirlist[count++] = 3;
128 elmex 1.1 }
129    
130     /* look left */
131 root 1.3 if (xc > 2 && yc > 2 && yc < ysize - 2) /* it is valid to look down */
132 elmex 1.1 {
133 root 1.17 int cleartest = maze[xc - 1][yc] + maze[xc - 1][yc - 1] + maze[xc - 1][yc + 1]
134     + maze[xc - 2][yc] + maze[xc - 2][yc - 1] + maze[xc - 2][yc + 1];
135 root 1.2
136 root 1.3 if (cleartest == 0)
137 root 1.12 dirlist[count++] = 4;
138 elmex 1.1 }
139    
140 root 1.3 if (count == 0)
141     return -1; /* failed to find any clear points */
142 elmex 1.1
143     /* choose a random direction */
144 root 1.12 switch (dirlist [rmg_rndm (count)])
145 elmex 1.1 {
146 root 1.5 case 1: /* up */
147 root 1.20 p.x = xc;
148     p.y = yc + 1;
149 root 1.12 break;
150    
151 root 1.5 case 2: /* down */
152 root 1.20 p.x = xc;
153     p.y = yc - 1;
154 root 1.12 break;
155    
156 root 1.5 case 3: /* right */
157 root 1.20 p.x = xc + 1;
158     p.y = yc;
159 root 1.12 break;
160    
161 root 1.5 case 4: /* left */
162 root 1.20 p.x = xc - 1;
163     p.y = yc;
164 root 1.12 break;
165 elmex 1.1 }
166 root 1.12
167 elmex 1.1 return 1;
168     }
169    
170 root 1.13 /* the outsize interface routine: accepts sizes, returns a char
171     ** maze. option is a flag for either a sparse or a full maze. Sparse
172 root 1.21 mazes have sizable rooms. option = 3=full, 2=braided, 1=sparse, 0=rooms.*/
173 root 1.13 void
174 root 1.25 maze_gen (layout &maze, int subtype)
175 root 1.13 {
176 root 1.24 xsize = maze.w;
177     ysize = maze.h;
178 root 1.20 ::maze = maze;
179 root 1.19
180 root 1.24 maze.clear ();
181     maze.border ();
182 root 1.13
183 root 1.20 if (xsize < 4 || ysize < 4)
184     return;
185 root 1.13
186 root 1.23 seeds.reset (xsize * ysize);
187 root 1.21
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 root 1.13
197     /* recursively generate the walls of the maze */
198     /* first pop a random starting point */
199 root 1.23 while (seeds.size)
200 root 1.21 {
201     point p = pop_rand ();
202    
203     for (;;)
204     {
205     point pc;
206    
207     maze [p.x][p.y] = '#';
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 root 1.13
227 root 1.23 seeds.free ();
228 root 1.13 }
229