BuckraMega

Avatar


Programmer / Web Developer

Newport News, VA

January 1996


Learn Unity/C#

Awesome Thoery Idle



Note!

This site is under construction. Don't mind the mess - maybe someday this will be worth reading!

Welcome to Derp...Derp...Code!, my programming journal/blog. This site is more for me than anyone else, but if you are here and reading, that's great! You might wonder about the name - I might be good at programming, but I am a bad programmer, so I tend to derp a lot before producing worthwhile code.

Avatar6 Mar 2019

Coding a random dungeon generator, pt 2


Going down the rabbit hole

Alright, please check out Part 1 if you haven't yet. Cool? Now we start moving on to an area where I am not 100% sure what I was thinking, but it works. It the previous article, we set up the dungeon and its parameters, so now it is time to actually build the thing one square at a time. I do this in a wonky way, probably quite suboptimal, but that is why there are two derps before I get to the code. I remember struggling with all of this quite a bit when I was originally writing it - some things just took a while to figure out.

for ($x = 1; $x <= 15; $x++) {
	start_snake();
}
I called it start_snake because I imagined the code starting at a spot and snaking its way through the dungeon, creating squares as it went. Let's take a look at what that function does.

function start_snake() {

	global $cur_x, $cur_y, $max_x, $max_y, $map, $n, $s, $e, $w, $total_cells;
	
	$door = find_next_cell();
	
	if ($door) {
		$map[$cur_x][$cur_y] = generate_new_cell($door);
		$total_cells++;
	}
}
Yeah, more globals. I am bad at this, I already told you this. I see now how to build this better without globals, by passing variables and such. Remember, most of this code was written 10ish years ago, when I was even more-er bad than now. But now we start going down the rabbit hole, as this function calls another one that we must go dig into.

function find_next_cell() {

	global $cur_x, $cur_y, $map, $n, $s, $e, $w;
	$cur_cell = $map[$cur_x][$cur_y];
	
	$found = 0; $door[8] = 0; $door[4] = 0; $door[2] = 0; $door[1] = 0;;

	//FIND AN OPENING TO MOVE TO
	if ($cur_cell >= $s) {
		$door[8] = 1;
		$cur_cell -= $s;
	}

	if ($cur_cell >= $e) {
		$door[4] = 1;
		$cur_cell -= $e;
	}

	if ($cur_cell >= $w) {
		$door[2] = 1;
		$cur_cell -= $w;
	}

	if ($cur_cell >= $n) {
		$door[1] = 1;
	}
So this is a little obtuse. I drag in more globals, and I know those directionals should be constants, then I figure out the numerical value of the current cell, which describes where the doors are in the cell. I set $found to 0, which is later set to a direction if I successfully fund the next cell. I also initialize some door array variables to 0, which means no door, but I check for those later. And by later I mean the very next thing I do. South is worth 8, so if the value of the cell is equal to or more than 8, then I know that the cell has a door to the South. If it does, I subtract 8 from the cell value and set the door[8] value to 1 to denote a door to the south. I repeat this for East (4), West (2), and North (1). Clear as mud? Moving on.

//RANDOMLY CHOOSE A DIRECTION TO SEE IF THERE IS A DOOR THERE REPEAT UNTIL DOOR IS FOUND
	$i = 0;
	while (!$found) {
		$rand1 = rand(0,3);
		$rand = pow(2, $rand1);
		if ($door[$rand] == 1) {
			$found = $rand;
			//FOUND IS THE DIRECTION OF THE DOOR
		}
	}
Now, while an appropriate door is not found, I loop through a random choice trying to find a door. Once I do find it, I set $found to it. I feel like there is amore elegant way to do all of this, especially with the $door[] array, but this is what I came up with.

//MOVE CUR CELL TO THE DIRECTION OF THE DOOR
	$new_y = $cur_y;
	$new_x = $cur_x;
	if ($found == $s) {
		$new_y = $cur_y + 1;
	} else if ($found == $n) {
		$new_y = $cur_y - 1;
	} else if ($found == $e) {
		$new_x = $cur_x + 1;
	} else if ($found == $w) {
		$new_x = $cur_x - 1;
	}
This bit is pretty simple. Depending on which direction the door is, I determine a new value for the cell the door is going to.

//CHECK TO MAKE SURE THAT CELL DOESN'T ALREADY EXIST
	if ($map[$new_x][$new_y] > 0) {

		//CELL EXISTS, RECURSE AND DO IT OVER
		return 0;

	} else {
		$cur_x = $new_x;
		$cur_y = $new_y;

		//NOW NEW CELL LOCATION IS $CUR_X $CUR_Y
		//IT MUST HAVE A DOOR BACK TO THE PREVIOUS ROOM

		if ($found == $s) { //PREVIOUS CELL HAS A DOOR SOUTH
			return $n;
		} else if ($found == $n) {
			return $s;
		} else if ($found == $w) {
			return $e;
		} else {
			return $w;
		}
	}
I close out this process by first checking to see if the sqaure in that direction already has a cell created there. If it does, I return 0 which bubbles back up to the original start_snake loop and tries again. If the cell doesn't exist, I set the current coordinates as the new cell and return the value of the door back to the original cell, since each cell must have a door to the other. This value is returned into the $door variable back in the start_snake function which allows us to enter the if ($door) logic and get to the generate_new_cell function, which I will get into in the next article!

Because I solved this problem in this way, it is hard to see another way because my mind keep going down this path. I think there is probably an easier way to do it, but this is what I have for now. Someday, maybe, after I write all about it and fully understand it, I'll try to optimize it. Mayeb when I rewrite the code in C# for the idle version of the Awesome Theory! Yeah, someday!

Tags: Awesome Theory code dungeon generator functions globals random

Enter a comment

Name:
Comment (max 5K characters):

User comments

Current Working Links:

Acrophobia

Awesome Theory Demo





Known Bugs

Tags list: top margin errors when only one item on a line