Atrinik Server 2.5
random_maps/maze_gen.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00034 #include <global.h>
00035 
00037 typedef struct free_walls_struct
00038 {
00040     int *wall_x_list;
00041 
00043     int *wall_y_list;
00044 
00046     int wall_free_size;
00047 } free_walls_struct;
00048 
00049 static void fill_maze_full(char **maze, int x, int y ,int xsize, int ysize, free_walls_struct *free_walls);
00050 static void fill_maze_sparse(char **maze, int x, int y, int xsize, int ysize, free_walls_struct *free_walls);
00051 static void make_wall_free_list(int xsize, int ysize, free_walls_struct *free_walls);
00052 static void pop_wall_point(int *x, int *y, free_walls_struct *free_walls);
00053 static int find_free_point(char **maze, int *x, int *y, int xc, int yc, int xsize, int ysize);
00054 
00065 char **maze_gen(int xsize, int ysize, int option)
00066 {
00067     int i, j;
00068     struct free_walls_struct free_walls;
00069     /* allocate that array, set it up */
00070     char **maze = (char **) calloc(sizeof(char *), xsize);
00071 
00072     for (i = 0; i < xsize; i++)
00073     {
00074         maze[i] = (char *) calloc(sizeof(char), ysize);
00075     }
00076 
00077     /* Write the outer walls */
00078     for (i = 0; i < xsize; i++)
00079     {
00080         maze[i][0] = maze[i][ysize - 1] = '#';
00081     }
00082 
00083     for (j = 0;j < ysize; j++)
00084     {
00085         maze[0][j] = maze[xsize - 1][j] = '#';
00086     }
00087 
00088     /* Find how many free wall spots there are */
00089     free_walls.wall_free_size = 2 * (xsize - 4) + 2 * (ysize - 4);
00090 
00091     free_walls.wall_x_list = NULL;
00092     free_walls.wall_y_list = NULL;
00093 
00094     make_wall_free_list(xsize, ysize, &free_walls);
00095 
00096     /* Return the empty maze */
00097     if (free_walls.wall_free_size <= 0)
00098     {
00099         return maze;
00100     }
00101 
00102     /* recursively generate the walls of the maze */
00103     while (free_walls.wall_free_size > 0)
00104     {
00105         /* first pop a random starting point */
00106         pop_wall_point(&i, &j, &free_walls);
00107 
00108         if (option)
00109         {
00110             fill_maze_full(maze, i, j, xsize, ysize, &free_walls);
00111         }
00112         else
00113         {
00114             fill_maze_sparse(maze, i, j, xsize, ysize, &free_walls);
00115         }
00116     }
00117 
00118     /* clean up our intermediate data structures. */
00119     free(free_walls.wall_x_list);
00120     free(free_walls.wall_y_list);
00121 
00122     return maze;
00123 }
00124 
00134 static void make_wall_free_list(int xsize, int ysize, free_walls_struct *free_walls)
00135 {
00136     int i, j, count = 0;
00137 
00138     if (free_walls->wall_free_size < 0)
00139     {
00140         return;
00141     }
00142 
00143     /* allocate it */
00144     free_walls->wall_x_list = (int *) calloc(sizeof(int), free_walls->wall_free_size);
00145     free_walls->wall_y_list = (int *) calloc(sizeof(int), free_walls->wall_free_size);
00146 
00147     /* top and bottom wall */
00148     for (i = 2; i < xsize - 2; i++)
00149     {
00150         free_walls->wall_x_list[count] = i;
00151         free_walls->wall_y_list[count] = 0;
00152         count++;
00153 
00154         free_walls->wall_x_list[count] = i;
00155         free_walls->wall_y_list[count] = ysize - 1;
00156         count++;
00157     }
00158 
00159     /* left and right wall */
00160     for (j = 2; j < ysize - 2; j++)
00161     {
00162         free_walls->wall_x_list[count] = 0;
00163         free_walls->wall_y_list[count] = j;
00164         count++;
00165 
00166         free_walls->wall_x_list[count] = xsize - 1;
00167         free_walls->wall_y_list[count] = j;
00168         count++;
00169     }
00170 }
00171 
00177 static void pop_wall_point(int *x, int *y, free_walls_struct *free_walls)
00178 {
00179     int i = RANDOM() % free_walls->wall_free_size;
00180 
00181     *x = free_walls->wall_x_list[i];
00182     *y = free_walls->wall_y_list[i];
00183 
00184     /* Write the last array point here */
00185     free_walls->wall_x_list[i] = free_walls->wall_x_list[free_walls->wall_free_size - 1];
00186     free_walls->wall_y_list[i] = free_walls->wall_y_list[free_walls->wall_free_size - 1];
00187 
00188     free_walls->wall_free_size--;
00189 }
00190 
00204 static int find_free_point(char **maze, int *x, int *y, int xc, int yc, int xsize, int ysize)
00205 {
00206     /* we will randomly pick from this list, 1=up,2=down,3=right,4=left */
00207     int dirlist[4];
00208     /* # elements in dirlist */
00209     int count = 0;
00210 
00211     /* look up */
00212     if (yc < ysize - 2 && xc > 2 && xc < xsize - 2)
00213     {
00214         int cleartest = (int) maze[xc][yc + 1] + (int) maze[xc - 1][yc + 1] + (int) maze[xc + 1][yc + 1];
00215 
00216         cleartest += (int) maze[xc][yc + 2] + (int) maze[xc - 1][yc + 2] + (int) maze[xc + 1][yc + 2];
00217 
00218         if (cleartest == 0)
00219         {
00220             dirlist[count] = 1;
00221             count++;
00222         }
00223     }
00224 
00225     /* look down */
00226     if (yc > 2 && xc > 2 && xc < xsize - 2)
00227     {
00228         int cleartest = (int) maze[xc][yc - 1] + (int) maze[xc - 1][yc - 1] + (int) maze[xc + 1][yc - 1];
00229 
00230         cleartest += (int) maze[xc][yc - 2] + (int) maze[xc - 1][yc - 2] + (int) maze[xc + 1][yc - 2];
00231 
00232         if (cleartest == 0)
00233         {
00234             dirlist[count] = 2;
00235             count++;
00236         }
00237     }
00238 
00239     /* look right */
00240     if (xc < xsize - 2 && yc > 2 && yc < ysize - 2)
00241     {
00242         int cleartest = (int) maze[xc + 1][yc] + (int) maze[xc + 1][yc - 1] + (int) maze[xc + 1][yc + 1];
00243 
00244         cleartest += (int) maze[xc + 2][yc] + (int) maze[xc + 2][yc - 1] + (int) maze[xc + 2][yc + 1];
00245 
00246         if (cleartest == 0)
00247         {
00248             dirlist[count] = 3;
00249             count++;
00250         }
00251     }
00252 
00253     /* look left */
00254     if (xc > 2 && yc > 2 && yc < ysize - 2)
00255     {
00256         int cleartest = (int) maze[xc - 1][yc] + (int) maze[xc - 1][yc - 1] + (int) maze[xc - 1][yc + 1];
00257 
00258         cleartest += (int) maze[xc - 2][yc] + (int) maze[xc - 2][yc - 1] + (int) maze[xc - 2][yc + 1];
00259 
00260         if (cleartest == 0)
00261         {
00262             dirlist[count] = 4;
00263             count++;
00264         }
00265     }
00266 
00267     /* Failed to find any clear points */
00268     if (count == 0)
00269     {
00270         return -1;
00271     }
00272 
00273     /* choose a random direction */
00274     if (count > 1)
00275     {
00276         count = RANDOM() % count;
00277     }
00278     else
00279     {
00280         count = 0;
00281     }
00282 
00283     switch (dirlist[count])
00284     {
00285         case 1:
00286             *y = yc + 1;
00287             *x = xc;
00288 
00289             break;
00290 
00291         case 2:
00292             *y = yc - 1;
00293             *x = xc;
00294 
00295             break;
00296 
00297         case 3:
00298             *y = yc;
00299             *x = xc + 1;
00300 
00301             break;
00302 
00303         case 4:
00304             *x = xc - 1;
00305             *y = yc;
00306 
00307             break;
00308 
00309         default:
00310             return -1;
00311     }
00312 
00313     return 1;
00314 }
00315 
00326 static void fill_maze_full(char **maze, int x, int y, int xsize, int ysize, free_walls_struct *free_walls)
00327 {
00328     int xc, yc;
00329 
00330     /* Write a wall here */
00331     maze[x][y] = '#';
00332 
00333     /* Decide if we're going to pick from the wall_free_list */
00334     if (RANDOM() % 4 && free_walls->wall_free_size > 0)
00335     {
00336         pop_wall_point(&xc, &yc, free_walls);
00337         fill_maze_full(maze, xc, yc, xsize, ysize, free_walls);
00338     }
00339 
00340     /* Change the if to a while for a complete maze.  */
00341     while (find_free_point(maze, &xc, &yc, x, y, xsize, ysize) != -1)
00342     {
00343         fill_maze_full(maze, xc, yc, xsize, ysize, free_walls);
00344     }
00345 }
00346 
00356 static void fill_maze_sparse(char **maze, int x, int y, int xsize, int ysize, free_walls_struct *free_walls)
00357 {
00358     int xc, yc;
00359 
00360     /* Write a wall here */
00361     maze[x][y] = '#';
00362 
00363     /* Decide if we're going to pick from the wall_free_list */
00364     if (RANDOM() % 4 && free_walls->wall_free_size > 0)
00365     {
00366         pop_wall_point(&xc, &yc, free_walls);
00367         fill_maze_sparse(maze, xc, yc, xsize, ysize, free_walls);
00368     }
00369 
00370     /* Change the if to a while for a complete maze.  */
00371     if (find_free_point(maze, &xc, &yc, x, y, xsize, ysize) != -1)
00372     {
00373         fill_maze_sparse(maze, xc, yc, xsize, ysize, free_walls);
00374     }
00375 }