Crossfire Server, Branches 1.12  R18729
maze_gen.c
Go to the documentation of this file.
1 /*
2  CrossFire, A Multiplayer game for X-windows
3 
4  Copyright (C) 2001 Mark Wedel & Crossfire Development Team
5  Copyright (C) 1992 Frank Tore Johansen
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your 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 GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21  The authors can be reached via e-mail at crossfire-devel@real-time.com
22 */
23 
31 /* we need to maintain a list of wall points to generate
32  * reasonable mazes: a straightforward recursive random walk maze
33  * generator would generate a map with a trivial circle-the-outer-wall solution
34  */
35 
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <global.h>
39 #include <maze_gen.h>
40 #include <time.h>
41 
43 typedef struct free_walls_struct {
44  int *wall_x_list;
45  int *wall_y_list;
48 
49 static void fill_maze_full(char **maze, int x, int y, int xsize, int ysize, free_walls_struct *);
50 static void fill_maze_sparse(char **maze, int x, int y, int xsize, int ysize, free_walls_struct *);
51 static void make_wall_free_list(int xsize, int ysize, free_walls_struct *);
52 static void pop_wall_point(int *x, int *y, free_walls_struct *);
53 static int find_free_point(char **maze, int *x, int *y, int xc, int yc, int xsize, int ysize);
54 
68 char **maze_gen(int xsize, int ysize, int option) {
69  int i, j;
70  struct free_walls_struct free_walls;
71 
72  /* allocate that array, set it up */
73  char **maze = (char **)calloc(sizeof(char *), xsize);
74  for (i = 0; i < xsize; i++) {
75  maze[i] = (char *)calloc(sizeof(char), ysize);
76  }
77 
78  /* write the outer walls */
79  for (i = 0; i < xsize; i++)
80  maze[i][0] = maze[i][ysize-1] = '#';
81  for (j = 0; j < ysize; j++)
82  maze[0][j] = maze[xsize-1][j] = '#';
83 
84 
85  /* find how many free wall spots there are */
86  free_walls.wall_free_size = 2*(xsize-4)+2*(ysize-4);
87  free_walls.wall_x_list = NULL;
88  free_walls.wall_y_list = NULL;
89 
90  make_wall_free_list(xsize, ysize, &free_walls);
91 
92  /* return the empty maze */
93  if (free_walls.wall_free_size <= 0)
94  return maze;
95 
96  /* recursively generate the walls of the maze */
97  /* first pop a random starting point */
98  while (free_walls.wall_free_size > 0) {
99  pop_wall_point(&i, &j, &free_walls);
100  if (option)
101  fill_maze_full(maze, i, j, xsize, ysize, &free_walls);
102  else
103  fill_maze_sparse(maze, i, j, xsize, ysize, &free_walls);
104  }
105 
106  /* clean up our intermediate data structures. */
107  free(free_walls.wall_x_list);
108  free(free_walls.wall_y_list);
109 
110  return maze;
111 }
112 
123 static void make_wall_free_list(int xsize, int ysize, free_walls_struct *free_walls) {
124  int i, j, count;
125 
126  count = 0; /* entries already placed in the free list */
127  /*allocate it*/
128  if (free_walls->wall_free_size < 0)
129  return;
130  free_walls->wall_x_list = (int *)calloc(sizeof(int), free_walls->wall_free_size);
131  free_walls->wall_y_list = (int *)calloc(sizeof(int), free_walls->wall_free_size);
132 
133 
134  /* top and bottom wall */
135  for (i = 2; i < xsize-2; i++) {
136  free_walls->wall_x_list[count] = i;
137  free_walls->wall_y_list[count] = 0;
138  count++;
139  free_walls->wall_x_list[count] = i;
140  free_walls->wall_y_list[count] = ysize-1;
141  count++;
142  }
143 
144  /* left and right wall */
145  for (j = 2; j < ysize-2; j++) {
146  free_walls->wall_x_list[count] = 0;
147  free_walls->wall_y_list[count] = j;
148  count++;
149  free_walls->wall_x_list[count] = xsize-1;
150  free_walls->wall_y_list[count] = j;
151  count++;
152  }
153 }
154 
163 static void pop_wall_point(int *x, int *y, free_walls_struct *free_walls) {
164  int index = RANDOM()%free_walls->wall_free_size;
165  *x = free_walls->wall_x_list[index];
166  *y = free_walls->wall_y_list[index];
167  /* write the last array point here */
168  free_walls->wall_x_list[index] = free_walls->wall_x_list[free_walls->wall_free_size-1];
169  free_walls->wall_y_list[index] = free_walls->wall_y_list[free_walls->wall_free_size-1];
170  free_walls->wall_free_size--;
171 }
172 
191 static int find_free_point(char **maze, int *x, int *y, int xc, int yc, int xsize, int ysize) {
192  /* we will randomly pick from this list, 1=up, 2=down, 3=right, 4=left */
193  int dirlist[4];
194  int count = 0; /* # elements in dirlist */
195 
196  /* look up */
197  if (yc < ysize-2 && xc > 2 && xc < xsize-2) {
198  int cleartest = (int)maze[xc][yc+1]+(int)maze[xc-1][yc+1]+(int)maze[xc+1][yc+1];
199 
200  cleartest += (int)maze[xc][yc+2]+(int)maze[xc-1][yc+2]+(int)maze[xc+1][yc+2];
201  if (cleartest == 0) {
202  dirlist[count] = 1;
203  count++;
204  }
205  }
206 
207  /* look down */
208  if (yc > 2 && xc > 2 && xc < xsize-2) {
209  int cleartest = (int)maze[xc][yc-1]+(int)maze[xc-1][yc-1]+(int)maze[xc+1][yc-1];
210 
211  cleartest += (int)maze[xc][yc-2]+(int)maze[xc-1][yc-2]+(int)maze[xc+1][yc-2];
212  if (cleartest == 0) {
213  dirlist[count] = 2;
214  count++;
215  }
216  }
217 
218 
219  /* look right */
220  if (xc < xsize-2 && yc > 2 && yc < ysize-2) {
221  int cleartest = (int)maze[xc+1][yc]+(int)maze[xc+1][yc-1]+(int)maze[xc+1][yc+1];
222 
223  cleartest += (int)maze[xc+2][yc]+(int)maze[xc+2][yc-1]+(int)maze[xc+2][yc+1];
224  if (cleartest == 0) {
225  dirlist[count] = 3;
226  count++;
227  }
228  }
229 
230 
231  /* look left */
232  if (xc > 2 && yc > 2 && yc < ysize-2) {
233  int cleartest = (int)maze[xc-1][yc]+(int)maze[xc-1][yc-1]+(int)maze[xc-1][yc+1];
234 
235  cleartest += (int)maze[xc-2][yc]+(int)maze[xc-2][yc-1]+(int)maze[xc-2][yc+1];
236  if (cleartest == 0) {
237  dirlist[count] = 4;
238  count++;
239  }
240  }
241 
242  if (count == 0)
243  return -1; /* failed to find any clear points */
244 
245  /* choose a random direction */
246  if (count > 1)
247  count = RANDOM()%count;
248  else
249  count = 0;
250  switch (dirlist[count]) {
251  case 1: { /* up */
252  *y = yc+1;
253  *x = xc;
254  break;
255  };
256 
257  case 2: { /* down */
258  *y = yc-1;
259  *x = xc;
260  break;
261  };
262 
263  case 3: { /* right */
264  *y = yc;
265  *x = xc+1;
266  break;
267  }
268 
269  case 4: { /* left */
270  *x = xc-1;
271  *y = yc;
272  break;
273  }
274 
275  default: { /* ??? */
276  return -1;
277  }
278  }
279  return 1;
280 }
281 
297 static void fill_maze_full(char **maze, int x, int y, int xsize, int ysize, free_walls_struct *free_walls) {
298  int xc, yc;
299 
300  /* write a wall here */
301  maze[x][y] = '#';
302 
303  /* decide if we're going to pick from the wall_free_list */
304  if (RANDOM()%4 && free_walls->wall_free_size > 0) {
305  pop_wall_point(&xc, &yc, free_walls);
306  fill_maze_full(maze, xc, yc, xsize, ysize, free_walls);
307  }
308 
309  /* change the if to a while for a complete maze. */
310  while (find_free_point(maze, &xc, &yc, x, y, xsize, ysize) != -1) {
311  fill_maze_full(maze, xc, yc, xsize, ysize, free_walls);
312  }
313 }
314 
329 static void fill_maze_sparse(char **maze, int x, int y, int xsize, int ysize, free_walls_struct *free_walls) {
330  int xc, yc;
331 
332  /* write a wall here */
333  maze[x][y] = '#';
334 
335  /* decide if we're going to pick from the wall_free_list */
336  if (RANDOM()%4 && free_walls->wall_free_size > 0) {
337  pop_wall_point(&xc, &yc, free_walls);
338  fill_maze_sparse(maze, xc, yc, xsize, ysize, free_walls);
339  }
340 
341  /* change the if to a while for a complete maze. */
342  if (find_free_point(maze, &xc, &yc, x, y, xsize, ysize) != -1) {
343  fill_maze_sparse(maze, xc, yc, xsize, ysize, free_walls);
344  }
345 }
static void fill_maze_full(char **maze, int x, int y, int xsize, int ysize, free_walls_struct *)
Definition: maze_gen.c:297
int * wall_x_list
Definition: maze_gen.c:44
static void make_wall_free_list(int xsize, int ysize, free_walls_struct *)
Definition: maze_gen.c:123
static void fill_maze_sparse(char **maze, int x, int y, int xsize, int ysize, free_walls_struct *)
Definition: maze_gen.c:329
static int find_free_point(char **maze, int *x, int *y, int xc, int yc, int xsize, int ysize)
Definition: maze_gen.c:191
struct free_walls_struct free_walls_struct
static void pop_wall_point(int *x, int *y, free_walls_struct *)
Definition: maze_gen.c:163
char ** maze_gen(int xsize, int ysize, int option)
Definition: maze_gen.c:68
int * wall_y_list
Definition: maze_gen.c:45