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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines