--- deliantra/server/random_maps/maze_gen.C 2008/05/04 14:12:37 1.11
+++ deliantra/server/random_maps/maze_gen.C 2010/06/29 18:27:02 1.22
@@ -1,3 +1,25 @@
+/*
+ * This file is part of Deliantra, the Roguelike Realtime MMORPG.
+ *
+ * Copyright (©) 2005,2006,2007,2008,2009 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
+ * Copyright (©) Crossfire Development Team (restored, original file without copyright notice)
+ *
+ * Deliantra is free software: you can redistribute it and/or modify it under
+ * the terms of the Affero GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the Affero GNU General Public License
+ * and the GNU General Public License along with this program. If not, see
+ * .
+ *
+ * The authors can be reached via e-mail to
+ */
/* peterm@langmuir.eecs.berkeley.edu: this function generates a random
blocked maze with the property that there is only one path from one spot
@@ -15,263 +37,239 @@
reasonable mazes: a straightforward recursive random walk maze
generator would generate a map with a trivial circle-the-outer-wall solution */
+#include
+
#include
#include "random_map.h"
#include "rproto.h"
-/* global variables that everyone needs: don't want to pass them in
- as parameters every time. */
-int *wall_x_list = 0;
-int *wall_y_list = 0;
-int wall_free_size = 0;
-
-/* heuristically, we need to change wall_chance based on the size of
- the maze. */
-
-int wall_chance;
-
-/* the outsize interface routine: accepts sizes, returns a char
-** maze. option is a flag for either a sparse or a full maze. Sparse
-mazes have sizable rooms. option = 1, full, 0, sparse.*/
-void
-maze_gen (Layout maze, int option)
+struct point
{
- maze->clear ();
- maze->border ();
+ short x;
+ short y;
- /* find how many free wall spots there are */
- wall_free_size = 2 * (maze->w - 4) + 2 * (maze->h - 4);
+ point ()
+ {
+ }
+
+ point (int x, int y)
+ : x(x), y(y)
+ {
+ }
+};
- make_wall_free_list (maze->w, maze->h);
-
- /* return the empty maze */
- if (wall_free_size <= 0)
- return;
-
- /* recursively generate the walls of the maze */
- /* first pop a random starting point */
- while (wall_free_size > 0)
- {
- int i, j;
-
- pop_wall_point (&i, &j);
+/* global variables that everyone needs: don't want to pass them in
+ as parameters every time. */
+static point *seed_list;
+static int seed_max, seed_size;
+static int xsize, ysize;
+static char **maze;
- if (option)
- fill_maze_full (maze, i, j, maze->w, maze->h);
- else
- fill_maze_sparse (maze, i, j, maze->w, maze->h);
- }
+static void
+push (point p)
+{
+ assert (seed_size < seed_max);
- /* clean up our intermediate data structures. */
+ seed_list [seed_size++] = p;
- free (wall_x_list);
- free (wall_y_list);
+ maze [p.x][p.y] = '#';
}
/* the free wall points are those outer points which aren't corners or
near corners, and don't have a maze wall growing out of them already. */
-void
-make_wall_free_list (int xsize, int ysize)
+static void
+push_walls ()
{
- int i, j, count;
-
- count = 0; /* entries already placed in the free list */
- /*allocate it */
- if (wall_free_size < 0)
- return;
-
- wall_x_list = (int *)calloc (sizeof (int), wall_free_size);
- wall_y_list = (int *)calloc (sizeof (int), wall_free_size);
-
/* top and bottom wall */
- for (i = 2; i < xsize - 2; i++)
+ for (int x = 2; x < xsize - 2; x++)
{
- wall_x_list[count] = i;
- wall_y_list[count] = 0;
- count++;
- wall_x_list[count] = i;
- wall_y_list[count] = ysize - 1;
- count++;
+ push (point (x, 0));
+ push (point (x, ysize - 1));
}
/* left and right wall */
- for (j = 2; j < ysize - 2; j++)
+ for (int y = 2; y < ysize - 2; y++)
{
- wall_x_list[count] = 0;
- wall_y_list[count] = j;
- count++;
- wall_x_list[count] = xsize - 1;
- wall_y_list[count] = j;
- count++;
+ push (point ( 0, y));
+ push (point (xsize - 1, y));
}
}
/* randomly returns one of the elements from the wall point list */
-void
-pop_wall_point (int *x, int *y)
+static point
+pop_rand ()
{
- int index = rmg_rndm (wall_free_size);
+ int index = rmg_rndm (seed_size);
+
+ point p = seed_list [index];
- *x = wall_x_list[index];
- *y = wall_y_list[index];
/* write the last array point here */
- wall_x_list[index] = wall_x_list[wall_free_size - 1];
- wall_y_list[index] = wall_y_list[wall_free_size - 1];
- wall_free_size--;
+ seed_list [index] = seed_list [--seed_size];
+
+ return p;
}
/* find free point: randomly look for a square adjacent to this one where
we can place a new block without closing a path. We may only look
up, down, right, or left. */
-int
-find_free_point (char **maze, int *x, int *y, int xc, int yc, int xsize, int ysize)
+static int
+find_free_point (point &p, point pc)
{
-
-/* we will randomly pick from this list, 1=up,2=down,3=right,4=left */
+ /* we will randomly pick from this list, 1=up,2=down,3=right,4=left */
int dirlist[4];
int count = 0; /* # elements in dirlist */
+ int xc = pc.x;
+ int yc = pc.y;
+
/* look up */
if (yc < ysize - 2 && xc > 2 && xc < xsize - 2) /* it is valid to look up */
{
- int cleartest = (int) maze[xc][yc + 1] + (int) maze[xc - 1][yc + 1] + (int) maze[xc + 1][yc + 1];
-
- cleartest += (int) maze[xc][yc + 2] + (int) maze[xc - 1][yc + 2] + (int) maze[xc + 1][yc + 2];
+ int cleartest = maze[xc][yc + 1] + maze[xc - 1][yc + 1] + maze[xc + 1][yc + 1]
+ + maze[xc][yc + 2] + maze[xc - 1][yc + 2] + maze[xc + 1][yc + 2];
if (cleartest == 0)
- {
- dirlist[count] = 1;
- count++;
- }
+ dirlist[count++] = 1;
}
/* look down */
if (yc > 2 && xc > 2 && xc < xsize - 2) /* it is valid to look down */
{
- int cleartest = (int) maze[xc][yc - 1] + (int) maze[xc - 1][yc - 1] + (int) maze[xc + 1][yc - 1];
-
- cleartest += (int) maze[xc][yc - 2] + (int) maze[xc - 1][yc - 2] + (int) maze[xc + 1][yc - 2];
+ int cleartest = maze[xc][yc - 1] + maze[xc - 1][yc - 1] + maze[xc + 1][yc - 1]
+ + maze[xc][yc - 2] + maze[xc - 1][yc - 2] + maze[xc + 1][yc - 2];
if (cleartest == 0)
- {
- dirlist[count] = 2;
- count++;
- }
+ dirlist[count++] = 2;
}
/* look right */
if (xc < xsize - 2 && yc > 2 && yc < ysize - 2) /* it is valid to look left */
{
- int cleartest = (int) maze[xc + 1][yc] + (int) maze[xc + 1][yc - 1] + (int) maze[xc + 1][yc + 1];
-
- cleartest += (int) maze[xc + 2][yc] + (int) maze[xc + 2][yc - 1] + (int) maze[xc + 2][yc + 1];
+ int cleartest = maze[xc + 1][yc] + maze[xc + 1][yc - 1] + maze[xc + 1][yc + 1]
+ + maze[xc + 2][yc] + maze[xc + 2][yc - 1] + maze[xc + 2][yc + 1];
if (cleartest == 0)
- {
- dirlist[count] = 3;
- count++;
- }
+ dirlist[count++] = 3;
}
/* look left */
if (xc > 2 && yc > 2 && yc < ysize - 2) /* it is valid to look down */
{
- int cleartest = (int) maze[xc - 1][yc] + (int) maze[xc - 1][yc - 1] + (int) maze[xc - 1][yc + 1];
-
- cleartest += (int) maze[xc - 2][yc] + (int) maze[xc - 2][yc - 1] + (int) maze[xc - 2][yc + 1];
+ int cleartest = maze[xc - 1][yc] + maze[xc - 1][yc - 1] + maze[xc - 1][yc + 1]
+ + maze[xc - 2][yc] + maze[xc - 2][yc - 1] + maze[xc - 2][yc + 1];
if (cleartest == 0)
- {
- dirlist[count] = 4;
- count++;
- }
+ dirlist[count++] = 4;
}
if (count == 0)
return -1; /* failed to find any clear points */
/* choose a random direction */
- if (count > 1)
- count = rmg_rndm (count);
- else
- count = 0;
-
- switch (dirlist[count])
+ switch (dirlist [rmg_rndm (count)])
{
case 1: /* up */
- {
- *y = yc + 1;
- *x = xc;
- break;
- };
+ p.x = xc;
+ p.y = yc + 1;
+ break;
+
case 2: /* down */
- {
- *y = yc - 1;
- *x = xc;
- break;
- };
+ p.x = xc;
+ p.y = yc - 1;
+ break;
+
case 3: /* right */
- {
- *y = yc;
- *x = xc + 1;
- break;
- }
+ p.x = xc + 1;
+ p.y = yc;
+ break;
+
case 4: /* left */
- {
- *x = xc - 1;
- *y = yc;
- break;
- }
- default: /* ??? */
- return -1;
-
+ p.x = xc - 1;
+ p.y = yc;
+ break;
}
+
return 1;
}
-/* recursive routine which will fill every available space in the maze
- with walls*/
+/* the outsize interface routine: accepts sizes, returns a char
+** maze. option is a flag for either a sparse or a full maze. Sparse
+mazes have sizable rooms. option = 3=full, 2=braided, 1=sparse, 0=rooms.*/
void
-fill_maze_full (char **maze, int x, int y, int xsize, int ysize)
+maze_gen (Layout maze, int subtype)
{
- int xc, yc;
+ xsize = maze->w;
+ ysize = maze->h;
+ ::maze = maze;
- /* write a wall here */
- maze[x][y] = '#';
+ maze->clear ();
+ maze->border ();
- /* decide if we're going to pick from the wall_free_list */
- if (rmg_rndm (4) && wall_free_size > 0)
- {
- pop_wall_point (&xc, &yc);
- fill_maze_full (maze, xc, yc, xsize, ysize);
- }
+ if (xsize < 4 || ysize < 4)
+ return;
+
+ seed_max = xsize * ysize;
+ seed_size = 0;
+ seed_list = salloc (seed_max);
+
+ if (subtype > 0)
+ push_walls ();
+
+ if (subtype == 0 || subtype == 2)
+ for (int i = (xsize + ysize) / 2; i; --i)
+ push (point (rmg_rndm (1, xsize - 2), rmg_rndm (1, ysize - 2)));
- /* change the if to a while for a complete maze. */
- while (find_free_point (maze, &xc, &yc, x, y, xsize, ysize) != -1)
+ bool full = subtype == 3;
+
+ /* recursively generate the walls of the maze */
+ /* first pop a random starting point */
+ while (seed_size)
{
- fill_maze_full (maze, xc, yc, xsize, ysize);
- }
-}
+ point p = pop_rand ();
-/* recursive routine which will fill much of the maze, but will leave
- some free spots (possibly large) toward the center.*/
-void
-fill_maze_sparse (char **maze, int x, int y, int xsize, int ysize)
-{
- int xc, yc;
+ for (;;)
+ {
+ point pc;
- /* write a wall here */
- maze[x][y] = '#';
+ maze [p.x][p.y] = '#';
- /* decide if we're going to pick from the wall_free_list */
- if (rmg_rndm (4) && wall_free_size > 0)
- {
- pop_wall_point (&xc, &yc);
- fill_maze_sparse (maze, xc, yc, xsize, ysize);
+ if (find_free_point (pc, p) < 0)
+ break;
+
+ if (full)
+ push (p);
+
+ if (!rmg_rndm (8))
+ {
+ if (!full)
+ push (pc);
+
+ break;
+ }
+
+ p = pc;
+ }
}
- /* change the if to a while for a complete maze. */
- if (find_free_point (maze, &xc, &yc, x, y, xsize, ysize) != -1)
- fill_maze_sparse (maze, xc, yc, xsize, ysize);
+ /* clean up our intermediate data structures. */
+ sfree (seed_list, seed_max);
}
+
+#if 0
+static struct demo
+{
+ demo ()
+ {
+ Layout layout (40, 25);
+ rmg_rndm.seed (time (0));
+
+ for(int i=1;i<10;++i)
+ {
+ maze_gen (layout, 3);
+ layout.print ();
+ }
+ exit (1);
+ }
+} demo;
+#endif