Last active
June 12, 2017 05:33
-
-
Save wuuff/b630f58b22216d1366091b4c6db36579 to your computer and use it in GitHub Desktop.
Simple random map generator (WIP)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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