Jump to content

Maps and distances between two specific objects etc . . .


Liquidedust

Recommended Posts

So sitting here coding a map populator in php and had to come up with a solution determining what the closest mountain on the map was in relation to the lakes the code spit out and ploink down on the map.

 

So while twiddling around I came up with the following but it feels very clunky and not quite such an elegant solution, so my question would be if you could wrap your heads around the code and maybe find a more elegant solution to what I am doing.

 

For reference the $mapdimensional_gridtypes array just looks like:

 

[x-coordinates][y-coordinates] => type of grid

 

foreach($mapdimensional_gridtypes as $key => $value) { // grab all mountains and lakes and their respective co-ordinates from the $mapdimensional_gridtypes array

foreach($value as $value_key => $value_value) {

	if($value_value == "lake") {

		$find_lakes[] = $key.",".$value_key;

	}

	if($value_value == "mountains") {

		$find_mountains[] = $key.",".$value_key;

	}

}

}

foreach($find_lakes as $key => $lake_value) { // calculate the distance between each lake and each mountain

$exploded_lake = explode(",", $lake_value);

foreach($find_mountains as $mountain_value) {

	$exploded_mountain = explode(",", $mountain_value);

	// some Pythagoras theorem to calculate the distance between the objects
	$a_distance = $exploded_lake[0] - $exploded_mountain[0];
	$b_distance = $exploded_lake[1] - $exploded_mountain[1];
	$lake_mountain_offset[$lake_value][$mountain_value] = sqrt( pow($a_distance,2) + pow($b_distance,2) );

}

}

foreach($lake_mountain_offset as $key => $value) { // grab the nearest mountain and its key (co-ordinates) for every lake and output in an array with the following format [lake co-ordinate]["mountain co-ordinates => distance"] (each record in the array will look something like [2,3] => "1,8 => 2")

asort($value);
$lake_mountain_offset_output[$key] = key($value)." = > ".min($value);

}

 

I mean the above code works and everything, but having a complete brianfart when it comes to improving it right now. I am somewhat stumped if this really is such a good solution to the problem since this feels very clunky code-wise. So basically just want a second opinion on it all more or less and any suggestion on what could be done in a better and/or more elegant way.

 

Oh yeah, the reason I need to calculate this is that I need to populate the map with rivers after this. I want each river to flow from a mountain to a lake and always take the shortest distance possible. Therefore need to know which mountain is closest to each lake before I draw the rivers.

Link to comment
Share on other sites

What you've done there makes sense to me.  You could calculate the minimum distance on the fly instead of by sorting afterwards if you wanted to.

 

Hmm, you mean to change this:

foreach($find_lakes as $key => $lake_value) { // calculate the distance between each lake and each mountain

$exploded_lake = explode(",", $lake_value);

foreach($find_mountains as $mountain_value) {

	$exploded_mountain = explode(",", $mountain_value);

	// some Pythagoras theorem to calculate the distance between the objects
	$a_distance = $exploded_lake[0] - $exploded_mountain[0];
	$b_distance = $exploded_lake[1] - $exploded_mountain[1];
	$lake_mountain_offset[$lake_value][$mountain_value] = sqrt( pow($a_distance,2) + pow($b_distance,2) );

}

}

 

into something like this:

foreach($find_lakes as $key => $lake_value) { // calculate the distance between each lake and each mountain

$exploded_lake = explode(",", $lake_value);

foreach($find_mountains as $mountain_value) {

	$exploded_mountain = explode(",", $mountain_value);

	// some Pythagoras theorem to calculate the distance between the objects
	$a_distance = $exploded_lake[0] - $exploded_mountain[0];
	$b_distance = $exploded_lake[1] - $exploded_mountain[1];

	if( isset($lake_mountain_offset_output_v2[$lake_value]) ) {

		$check_explode = explode("|", $lake_mountain_offset_output_v2[$lake_value]);

		if($check_explode[1] > sqrt( pow($a_distance,2) + pow($b_distance,2) )){

			$lake_mountain_offset_output_v2[$lake_value] = $mountain_value."|".sqrt( pow($a_distance,2) + pow($b_distance,2) );

		}

	} else {

		$lake_mountain_offset_output_v2[$lake_value] = $mountain_value."|".sqrt( pow($a_distance,2) + pow($b_distance,2) );

	}

}

}

 

Or something along those lines?

Link to comment
Share on other sites

In the end I went with this solution to the problem, slightly more readable and elegant I think

 

$lake_mountain_offset_output = array();

foreach($the_lakes as $lake_key => $lake_value) { // calculate the distance between each lake and each mountain - this loops through all lakes

$lake_coord_index = key($lake_value).",".$lake_value[key($lake_value)]; // get the current lake co-cordinates so we doesn't have to recalculate them more then once per loop

foreach($the_mountains as $mountain_key => $mountain_value) { // This loops through all mountains for each lake and compares the distances

	$mountain_coord_index = key($mountain_value).",".$mountain_value[key($mountain_value)]; // get the current mountain co-cordinates

	// some Pythagoras theorem to calculate the distance between the current lake and current mountain
	$a_distance = key($lake_value) - key($mountain_value);
	$b_distance = $lake_value[key($lake_value)] - $mountain_value[key($mountain_value)];
	$current_offset = sqrt( pow($a_distance,2) + pow($b_distance,2) );

	if( isset($lake_mountain_offset_output[$lake_coord_index ]) ) { // checks to see if the current lake is in $lake_mountain_offset_output array

		$check_explode = explode("|", $lake_mountain_offset_output[$lake_coord_index ]); // get the currently inserted mountains distance from the current lake in the $lake_mountain_offset_output array

		if($check_explode[1] > $current_offset ){ // check if this mountain is closer to the lake then the value currently in $lake_mountain_offset_output array

			$lake_mountain_offset_output[$lake_coord_index ] = $mountain_coord_index."|".$current_offset; // if its closer update the $lake_mountain_offset_output array with this mountains co-ordinates and distance from the lake

		}

	} else { // if the current lake isn't present in the $lake_mountain_offset_output array, insert it

		$lake_mountain_offset_output[$lake_coord_index ] = $mountain_coord_index."|".$current_offset;

	}

}

}

Link to comment
Share on other sites

Yep that's what I meant.

 

I think you can improve readability with a few small functions, especially a distance() function.  Then it'll read more like pseudo-code.

 

I think we have come as far as we can get now, unless you have any other ideas one might try to make it more elegant and run faster :)

 

Latest Version:

$lake_mountain_offset_output = array();

foreach($the_lakes as $lake_value) { // calculate the distance between each lake and each mountain - this loops through all lakes

$lake_coord_index = key($lake_value).",".$lake_value[key($lake_value)]; // get the current lake co-cordinates so we doesn't have to recalculate them more then once per loop

foreach($the_mountains as $mountain_value) { // This loops through all mountains for each lake and compares the distances

	$mountain_coord_index = key($mountain_value).",".$mountain_value[key($mountain_value)]; // get the current mountain co-cordinates

	// get the offset between the objects by passing the relevant variables to object_distance()
	$current_offset = object_distance( key($lake_value) , $lake_value[key($lake_value)] , key($mountain_value) , $mountain_value[key($mountain_value)] );

	if( isset($lake_mountain_offset_output[$lake_coord_index]) ) { // checks to see if the current lake is in $lake_mountain_offset_output array

		$check_explode = explode("|", $lake_mountain_offset_output[$lake_coord_index]); // get the currently inserted mountains distance from the current lake in the $lake_mountain_offset_output array

		if($check_explode[1] > $current_offset ){ // check if this mountain is closer to the lake then the value currently in $lake_mountain_offset_output array

			$lake_mountain_offset_output[$lake_coord_index] = $mountain_coord_index."|".$current_offset; // if its closer update the $lake_mountain_offset_output array with this mountains co-ordinates and distance from the lake

		}

	} else { // if the current lake isn't present in the $lake_mountain_offset_output array, insert it

		$lake_mountain_offset_output[$lake_coord_index] = $mountain_coord_index."|".$current_offset;

	}

}

}

Link to comment
Share on other sites

"Elegant" and "run faster" are two different goals :)  For something like this I would go for extendability and reusability before anything else, as you're likely to modify it in the future.  And if rivers are only generated infrequently, there's probably not a need to make it run faster, unless it's running very slowly already.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.