Skip to content

Instantly share code, notes, and snippets.

@wuuff
Last active June 12, 2017 05:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wuuff/b630f58b22216d1366091b4c6db36579 to your computer and use it in GitHub Desktop.
Save wuuff/b630f58b22216d1366091b4c6db36579 to your computer and use it in GitHub Desktop.
Simple random map generator (WIP)
#include <stdio.h>
#include <stdlib.h>
#define MAPSIZE 64
void mapinit(char map[][MAPSIZE], int width, int height);
void mapgen(char map[][MAPSIZE], int mapwidth, int mapheight, int startx, int starty, int endx, int endy);
void mapprint(char map[][MAPSIZE], int width, int height);
void mapinit(char map[][MAPSIZE], int width, int height){
int i,j;
//Generate walls around the edges
for( i = 0; i < width; i++ ){
map[0][i] = 1;
map[height-1][i] = 1;
}
for( j = 0; j < height; j++ ){
map[j][0] = 1;
map[j][width-1] = 1;
}
}
#define HORIZONTAL 0
#define VERTICAL 1
#define MIN_WIDTH 6
#define MIN_HEIGHT 8
#define HALL_CHANCE 40
#define MIN_HALL_WIDTH 8
#define MIN_HALL_HEIGHT 10
#define MAX_HALL_WIDTH 18
#define MAX_HALL_HEIGHT 20
#define EXTRA_DOOR 10
#define REM_WALL_CHANCE 25
#define MAX_REM_WALL 10
void mapgen(char map[][MAPSIZE], int mapwidth, int mapheight, int startx, int starty, int endx, int endy){
int i,j,orientation,position,door,door2,doorcount,hall,colspacex,colspacey,remwall;
int width = endx-startx;
int height = endy-starty;
if( width < MIN_WIDTH && height < MIN_HEIGHT ){
return;
}
//Determine whether to generate a big hall with pillars or not.
//The size of the room determines the column spacing for now
if( width >= MIN_HALL_WIDTH && height >= MIN_HALL_HEIGHT && width < MAX_HALL_WIDTH && height < MAX_HALL_HEIGHT ){
hall = rand()%100;//Percent chance out of 100
if( HALL_CHANCE > hall ){
//Place room columns as densely as the room supports
//IF you can divide the room into columns evenly
//but make sure there is greater than one space between columns
colspacex = width;
if( colspacex%2 != 0 ){
colspacex--;
}
while( colspacex%2 == 0 && colspacex > 4 ) colspacex /= 2;
colspacey = height;
if( colspacey%4 != 0 )
{
while( colspacey%4 != 0 ) colspacey++;
}
while( colspacey%4 == 0 && colspacey > 4 ) colspacey /= 4;
for( i = startx+colspacex; i < startx + width - 1; i+=colspacex ){
for( j = starty+colspacey; j < starty + height - 2; j+=colspacey ){
map[j][i] = 1;
}
}
return;//Do not subdivide; return immediately
}
}
//Determine whether we will split the space
//horizontally or vertically by choosing whichever
//orientation is larger (this avoids extremely long rooms)
if( width >= height ){
//If there is a door (or more than one door!) into a small room,
//we may not be able to generate a wall in any location!
//so abort if room is min + number of horiz door tiles
doorcount = 0;
for( i = startx; i < endx; i++ ){
if( map[starty][i] == 0 ) doorcount++;
if( map[endy][i] == 0 ) doorcount++;
}
if( width < MIN_WIDTH + doorcount ){
return;
}
orientation = VERTICAL;
//puts("Trying vertical");
}else{
//If there is a door (or more than one door!) into a small room,
//we may not be able to generate a wall in any location!
//so abort if room is min + number of vert door tiles
doorcount = 0;
for( i = starty; i < endy; i++ ){
if( map[i][startx] == 0 ) doorcount++;
if( map[i][endx] == 0 ) doorcount++;
}
if( height < MIN_HEIGHT + doorcount ){
return;
}
orientation = HORIZONTAL;
//puts("Trying horizontal");
}
//printf("startx %d, starty %d\n",startx,starty);
//mapprint(map,MAPSIZE,MAPSIZE);
position = -1;
if( orientation == HORIZONTAL ){
//Make sure the position is valid:
//1. It must have generated at least one number
//2. It must not be too close to existing walls
//3. It must not be over a door
while( position == -1 || position < starty + (MIN_HEIGHT/2) || position > endy - (MIN_HEIGHT/2) || map[position][startx] == 0 || map[position][endx] == 0 ){
position = starty + (rand()%height);
}
//Generate a door at a random position
door = startx + 1 + (rand()%(width-1));
//Generate an extra door if wall is long enough.
//Doors may overlap or be next to each other because such
//doors shouldn't be a problem and it might result in interesting maps.
//If it is not long enough set to -1 so it won't interfere
door2 = width >= EXTRA_DOOR ? startx + 1 + (rand()%(width-1)) : -1;
//printf("HORIZ %d\n",position);
for( i = startx+1; i < startx + width; i++ ){
if( i != door && i != door2 )
map[position][i] = 1;
}
//Determine whether or not we will remove a wall.
//We can't remove bottom and right walls because the regions beyond them
//haven't been generated yet, so we only try to remove top and left walls.
//If we are not on the map edges
if( startx > 0 && endx < mapwidth-1 ){
//If the new space is taller than it is wide
//and the wall is short enough
if( /*position - starty > width &&*/ position - starty < MAX_REM_WALL ){
remwall = 1;
//Check if there is no wall touching the wall we want to remove.
//If not, we can remove the wall
for( i = starty+1; i < position; i++ ){
if( map[i][startx-1] != 0 ){
remwall = 0;
break;
}
}
if( remwall && REM_WALL_CHANCE > (rand()%100) ){
for( i = starty+1; i < position; i++ ){
map[i][startx] = 0;//2;//Clear left side of upper half
}
}
}
//If the new space is taller than it is wide
//and the wall is short enough
if( /*endy - position > width &&*/ endy - position < MAX_REM_WALL ){
remwall = 1;
//Check if there is no wall touching the wall we want to remove.
//If not, we can remove the wall
for( i = position+1; i < endy; i++ ){
if( map[i][startx+1] != 0 ){
remwall = 0;
break;
}
}
if( remwall && REM_WALL_CHANCE > (rand()%100) ){
for( i = position+1; i < endy; i++ ){
map[i][startx] = 0;//4;//Clear left side of lower half
}
}
}
}
//Recursively call to fill the two new spaces we generated
mapgen(map, mapwidth, mapheight, startx, starty, endx,position);
mapgen(map, mapwidth, mapheight, startx, position, endx, endy);
}else if( orientation == VERTICAL ){
//Make sure the position is valid:
//1. It must have generated at least one number
//2. It must not be too close to existing walls
//3. It must not be over a door
while( position == -1 || position < startx + (MIN_WIDTH/2) || position > endx - (MIN_WIDTH/2) || map[starty][position] == 0 || map[endy][position] == 0 ){
position = startx + (rand()%width);
}
//Generate a door at a random position
//(allocating space for it to be 2 high)
door = starty + 1 + (rand()%(height-2));
//Generate an extra door if wall is long enough.
//Doors may overlap or be next to each other because such
//doors shouldn't be a problem and it might result in interesting maps.
//If it is not long enough set to -1 so it won't interfere
door2 = height >= EXTRA_DOOR ? starty + 1 + (rand()%(height-2)) : -1;
//printf("VERT %d\n",position);
for( i = starty+1; i < starty + height; i++ ){
if( i != door && i != door+1 && i != door2 && i != door2+1 )
map[i][position] = 1;
}
//Determine whether or not we will remove a wall.
//We can't remove bottom and right walls because the regions beyond them
//haven't been generated yet, so we only try to remove top and left walls.
//If we are not on the map edges
if( starty > 0 && endy < mapheight-1 ){
//If the new space is wider than it is tall
//and the wall is short enough
if( /*position - startx > height &&*/ position - startx < MAX_REM_WALL ){
remwall = 1;
//Check if there is no wall touching the wall we want to remove.
//If not, we can remove the wall
for( i = startx+1; i < position; i++ ){
if( map[starty-1][i] != 0 ){
remwall = 0;
break;
}
}
if( remwall && REM_WALL_CHANCE > (rand()%100) ){
for( i = startx+1; i < position; i++ ){
map[starty][i] = 0;//3;//Clear top side of left half
}
}
}
//If the new space is wider than it is tall
//and the wall is short enough
if( /*endx - position > height &&*/ endx - position < MAX_REM_WALL ){
remwall = 1;
//Check if there is no wall touching the wall we want to remove.
//If not, we can remove the wall
for( i = position+1; i < endx; i++ ){
if( map[starty-1][i] != 0 ){
remwall = 0;
break;
}
}
if( remwall && REM_WALL_CHANCE > (rand()%100) ){
for( i = position+1; i < endx; i++ ){
map[starty][i] = 0;//5;//Clear top side of right half
}
}
}
}
//Recursively call to fill the two new spaces we generated
mapgen(map, mapwidth, mapheight, startx, starty, position,endy);
mapgen(map, mapwidth, mapheight, position, starty, endx, endy);
}
}
void mapprint(char map[][MAPSIZE], int width, int height){
int i,j;
for( i = 0; i < height; i++ ){
for( j = 0; j < width; j++ ){
printf("%d",map[i][j]);
}
puts("");
}
}
char map[MAPSIZE][MAPSIZE];
int main(int argc, char** argv){
int seed = 42;
if( argc == 2 ){
seed = atoi(argv[1]);
}
srand(seed);//Can choose the seed to get the same map every time
mapinit(map,MAPSIZE,MAPSIZE);
mapgen(map,MAPSIZE,MAPSIZE,0,0,MAPSIZE-1,MAPSIZE-1);
mapprint(map,MAPSIZE,MAPSIZE);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment