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.19 by root, Sun Jun 27 16:36:12 2010 UTC vs.
Revision 1.27 by root, Sat Apr 23 04:56:52 2011 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 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.
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;
49static int wall_free_size = 0;
50static int xsize, ysize; 50static int xsize, ysize;
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}
51 66
52/* 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
53 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. */
54static void 69static void
55make_wall_free_list (int xsize, int ysize) 70push_walls ()
56{ 71{
57 int i, j, count;
58
59 count = 0; /* entries already placed in the free list */
60 /*allocate it */
61 if (wall_free_size < 0)
62 return;
63
64 wall_x_list = (int *)calloc (sizeof (int), wall_free_size);
65 wall_y_list = (int *)calloc (sizeof (int), wall_free_size);
66
67 /* top and bottom wall */ 72 /* top and bottom wall */
68 for (i = 2; i < xsize - 2; i++) 73 for (int x = 2; x < xsize - 2; x++)
69 { 74 {
70 wall_x_list[count] = i; 75 push (point (x, 0));
71 wall_y_list[count] = 0; 76 push (point (x, ysize - 1));
72 count++;
73 wall_x_list[count] = i;
74 wall_y_list[count] = ysize - 1;
75 count++;
76 } 77 }
77 78
78 /* left and right wall */ 79 /* left and right wall */
79 for (j = 2; j < ysize - 2; j++) 80 for (int y = 2; y < ysize - 2; y++)
80 {
81 wall_x_list[count] = 0;
82 wall_y_list[count] = j;
83 count++;
84 wall_x_list[count] = xsize - 1;
85 wall_y_list[count] = j;
86 count++;
87 } 81 {
88} 82 push (point ( 0, y));
89 83 push (point (xsize - 1, y));
90/* randomly returns one of the elements from the wall point list */ 84 }
91static void
92pop_wall_point (int *x, int *y)
93{
94 int index = rmg_rndm (wall_free_size);
95
96 *x = wall_x_list[index];
97 *y = wall_y_list[index];
98
99 /* write the last array point here */
100 wall_x_list[index] = wall_x_list[wall_free_size - 1];
101 wall_y_list[index] = wall_y_list[wall_free_size - 1];
102 wall_free_size--;
103} 85}
104 86
105/* 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
106we 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
107up, down, right, or left. */ 89up, down, right, or left. */
108static int 90static int
109find_free_point (char **maze, int *x, int *y, int xc, int yc) 91find_free_point (point &p, point pc)
110{ 92{
111 /* 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 */
112 int dirlist[4]; 94 int dirlist[4];
113 int count = 0; /* # elements in dirlist */ 95 int count = 0; /* # elements in dirlist */
114 96
97 int xc = pc.x;
98 int yc = pc.y;
99
115 /* look up */ 100 /* look up */
116 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 */
117 { 102 {
118 int cleartest = maze[xc][yc + 1] + maze[xc - 1][yc + 1] + maze[xc + 1][yc + 1] 103 int cleartest = maze[xc][yc + 1] + maze[xc - 1][yc + 1] + maze[xc + 1][yc + 1]
119 + maze[xc][yc + 2] + maze[xc - 1][yc + 2] + maze[xc + 1][yc + 2]; 104 + maze[xc][yc + 2] + maze[xc - 1][yc + 2] + maze[xc + 1][yc + 2];
157 142
158 /* choose a random direction */ 143 /* choose a random direction */
159 switch (dirlist [rmg_rndm (count)]) 144 switch (dirlist [rmg_rndm (count)])
160 { 145 {
161 case 1: /* up */ 146 case 1: /* up */
147 p.x = xc;
162 *y = yc + 1; 148 p.y = yc + 1;
163 *x = xc;
164 break; 149 break;
165 150
166 case 2: /* down */ 151 case 2: /* down */
152 p.x = xc;
167 *y = yc - 1; 153 p.y = yc - 1;
168 *x = xc;
169 break; 154 break;
170 155
171 case 3: /* right */ 156 case 3: /* right */
172 *y = yc;
173 *x = xc + 1; 157 p.x = xc + 1;
158 p.y = yc;
174 break; 159 break;
175 160
176 case 4: /* left */ 161 case 4: /* left */
177 *x = xc - 1; 162 p.x = xc - 1;
178 *y = yc; 163 p.y = yc;
179 break; 164 break;
180 } 165 }
181 166
182 return 1; 167 return 1;
183}
184
185/* recursive routine which will fill every available space in the maze
186 with walls*/
187static void
188fill_maze_full (char **maze, int x, int y)
189{
190 int xc, yc;
191
192 /* write a wall here */
193 maze[x][y] = '#';
194
195 /* decide if we're going to pick from the wall_free_list */
196 if (rmg_rndm (2) && wall_free_size > 0)
197 {
198 pop_wall_point (&xc, &yc);
199 fill_maze_full (maze, xc, yc);
200 }
201
202 /* change the while to an if for a sparse maze. */
203 while (find_free_point (maze, &xc, &yc, x, y) != -1)
204 fill_maze_full (maze, xc, yc);
205}
206
207/* recursive routine which will fill much of the maze, but will leave
208 some free spots (possibly large) toward the center.*/
209static void
210fill_maze_sparse (char **maze, int x, int y)
211{
212 int xc, yc;
213
214 /* write a wall here */
215 maze[x][y] = '#';
216
217 /* decide if we're going to pick from the wall_free_list */
218 if (rmg_rndm (2) && wall_free_size > 0)
219 {
220 pop_wall_point (&xc, &yc);
221 fill_maze_sparse (maze, xc, yc);
222 }
223
224 /* change the if to a while for a complete maze. */
225 if (find_free_point (maze, &xc, &yc, x, y) != -1)
226 fill_maze_sparse (maze, xc, yc);
227} 168}
228 169
229/* the outsize interface routine: accepts sizes, returns a char 170/* the outsize interface routine: accepts sizes, returns a char
230** 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
231mazes have sizable rooms. option = 1, full, 0, sparse.*/ 172mazes have sizable rooms. option = 3=full, 2=braided, 1=sparse, 0=rooms.*/
232void 173void
233maze_gen (Layout maze, int full) 174maze_gen (layout &maze, int subtype)
234{ 175{
235 maze->clear ();
236 maze->border ();
237
238 xsize = maze->w; 176 xsize = maze.w;
239 ysize = maze->h; 177 ysize = maze.h;
178 ::maze = maze;
240 179
241 /* find how many free wall spots there are */ 180 maze.clear ();
242 wall_free_size = 2 * (maze->w - 4) + 2 * (maze->h - 4); 181 maze.border ();
243 182
244 make_wall_free_list (maze->w, maze->h); 183 if (xsize < 4 || ysize < 4)
245
246 /* return the empty maze */
247 if (wall_free_size <= 0)
248 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;
249 196
250 /* recursively generate the walls of the maze */ 197 /* recursively generate the walls of the maze */
251 /* first pop a random starting point */ 198 /* first pop a random starting point */
252 while (wall_free_size > 0) 199 while (seeds.size)
253 { 200 {
254 int i, j; 201 point p = pop_rand ();
255 202
256 pop_wall_point (&i, &j); 203 for (;;)
204 {
205 point pc;
257 206
207 maze [p.x][p.y] = '#';
208
209 if (find_free_point (pc, p) < 0)
210 break;
211
258 if (full) 212 if (full)
259 fill_maze_full (maze, i, j); 213 push (p);
260 else
261 fill_maze_sparse (maze, i, j);
262 }
263 214
264 /* clean up our intermediate data structures. */ 215 if (!rmg_rndm (8))
216 {
217 if (!full)
218 push (pc);
265 219
266 free (wall_x_list); 220 break;
267 free (wall_y_list); 221 }
268}
269 222
270#if 1 223 p = pc;
271static struct demo
272{
273 demo ()
274 {
275 Layout layout (30, 30);
276 rmg_rndm.seed (time (0));
277
278 for(int i=1;i<10;++i)
279 {
280 maze_gen (layout, 1);
281 layout.print ();
282 } 224 }
283 exit (1);
284 } 225 }
285} demo; 226
286#endif 227 seeds.free ();
228}
229

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines