@ -5,6 +5,8 @@
*/
# include "path.h"
# include <array>
# include "gendung.h"
# include "objects.h"
@ -384,6 +386,143 @@ bool path_solid_pieces(Point startPosition, Point destinationPosition)
return rv ;
}
std : : optional < Point > FindClosestValidPosition ( const std : : function < bool ( Point ) > & posOk , Point startingPosition , unsigned int minimumRadius , unsigned int maximumRadius )
{
if ( minimumRadius > maximumRadius ) {
return { } ; // No valid search space with the given params.
}
if ( minimumRadius = = 0U ) {
if ( posOk ( startingPosition ) ) {
return startingPosition ;
}
}
if ( minimumRadius < = 1U & & maximumRadius > = 1U ) {
// unrolling the case for radius 1 to save having to guard the corner check in the loop below.
Point candidatePosition = startingPosition + Direction : : SouthWest ;
if ( posOk ( candidatePosition ) ) {
return candidatePosition ;
}
candidatePosition = startingPosition + Direction : : NorthEast ;
if ( posOk ( candidatePosition ) ) {
return candidatePosition ;
}
candidatePosition = startingPosition + Direction : : NorthWest ;
if ( posOk ( candidatePosition ) ) {
return candidatePosition ;
}
candidatePosition = startingPosition + Direction : : SouthEast ;
if ( posOk ( candidatePosition ) ) {
return candidatePosition ;
}
}
if ( maximumRadius > = 2U ) {
for ( int i = static_cast < int > ( std : : max ( minimumRadius , 2U ) ) ; i < = static_cast < int > ( std : : min ( maximumRadius , 50U ) ) ; i + + ) {
int x = 0 ;
int y = i ;
// special case the checks when x == 0 to save checking the same tiles twice
Point candidatePosition = startingPosition + Displacement { x , y } ;
if ( posOk ( candidatePosition ) ) {
return candidatePosition ;
}
candidatePosition = startingPosition + Displacement { x , - y } ;
if ( posOk ( candidatePosition ) ) {
return candidatePosition ;
}
while ( x < i - 1 ) {
x + + ;
candidatePosition = startingPosition + Displacement { - x , y } ;
if ( posOk ( candidatePosition ) ) {
return candidatePosition ;
}
candidatePosition = startingPosition + Displacement { x , y } ;
if ( posOk ( candidatePosition ) ) {
return candidatePosition ;
}
candidatePosition = startingPosition + Displacement { - x , - y } ;
if ( posOk ( candidatePosition ) ) {
return candidatePosition ;
}
candidatePosition = startingPosition + Displacement { x , - y } ;
if ( posOk ( candidatePosition ) ) {
return candidatePosition ;
}
}
// special case for inset corners
y - - ;
candidatePosition = startingPosition + Displacement { - x , y } ;
if ( posOk ( candidatePosition ) ) {
return candidatePosition ;
}
candidatePosition = startingPosition + Displacement { x , y } ;
if ( posOk ( candidatePosition ) ) {
return candidatePosition ;
}
candidatePosition = startingPosition + Displacement { - x , - y } ;
if ( posOk ( candidatePosition ) ) {
return candidatePosition ;
}
candidatePosition = startingPosition + Displacement { x , - y } ;
if ( posOk ( candidatePosition ) ) {
return candidatePosition ;
}
x + + ;
while ( y > 0 ) {
candidatePosition = startingPosition + Displacement { - x , y } ;
if ( posOk ( candidatePosition ) ) {
return candidatePosition ;
}
candidatePosition = startingPosition + Displacement { x , y } ;
if ( posOk ( candidatePosition ) ) {
return candidatePosition ;
}
candidatePosition = startingPosition + Displacement { - x , - y } ;
if ( posOk ( candidatePosition ) ) {
return candidatePosition ;
}
candidatePosition = startingPosition + Displacement { x , - y } ;
if ( posOk ( candidatePosition ) ) {
return candidatePosition ;
}
y - - ;
}
// as above, special case for y == 0
candidatePosition = startingPosition + Displacement { - x , y } ;
if ( posOk ( candidatePosition ) ) {
return candidatePosition ;
}
candidatePosition = startingPosition + Displacement { x , y } ;
if ( posOk ( candidatePosition ) ) {
return candidatePosition ;
}
}
}
return { } ;
}
# ifdef RUN_TESTS
int TestPathGetHeuristicCost ( Point startPosition , Point destinationPosition )
{