Hi.
I just wrote up some code to do the A* pathfinding algorithm for digging tunnels in a dungeon generator for a Roguelike game, and I'm getting some odd results. When I use it to dig a tunnel through free space between two points, I got this:
################################################################################
################################################################################
################################################################################
################################################################################
####.###########################################################################
#####.##########################################################################
######.#########################################################################
#######.########################################################################
########.#######################################################################
#########.######################################################################
##########.########################.############################################
###########.######################.#############################################
############.##################...##############################################
#############.##############...#################################################
##############.########.....####################################################
###############.##.....#########################################################
################..##############################################################
But that doesn't look good. I'd like to have it look like a straightish diagonal line between the two points, something sort of like what would come out of Bresenham's algorithm. Why is it goofy like that? I use a rounded-down Euclidean H-function (with sqrt), a same-cost G-function (i.e. move to any neighbor including diagonals is the same cost), and the open list priority queue is implemented via binary heap with supplementary tiebreaking key to enforce LIFO tie behavior (so it's more of a "stack" than a "queue" when it comes to ties) among nodes/tiles with equal F-cost. Neighbors are checked in a clockwise pattern starting at the upper-left.
If I switch the heap over to FIFO behavior (like a proper "queue"), I get this:
################################################################################
################################################################################
################################################################################
####.......#####################################################################
###########.......##############################################################
##################.....#########################################################
#######################.....####################################################
############################...#################################################
###############################...##############################################
##################################.#############################################
###################################.############################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
which looks a bit better, but the algorithm also seems to explore many more squares. And it's still got that "curve" which doesn't look too good. (Strange; it reminds me of the graph of the square root function. Is there something significant about that?) Both tunnels seem to have the same length (32 squares). I presume it has something to do with how it handles the multiple existent shortest paths between the points, but how do I get it to give me "nice" ones?
The code (C++) for the G, H functions is this:
float GCostFuncs_Flat(u16 y1, u16 x1, u16 y2, u16 x2)
{
return(BASE_COST);
}
float HCostFuncs_Euclidean(u16 y1, u16 x1, u16 y2, u16 x2)
{
double ydist(y2), xdist(x2);
ydist -= y1;
xdist -= x1;
return(floor(sqrt(ydist*ydist + xdist*xdist))*BASE_COST);
}
And yes, I've tested the heap code to make sure it didn't have any bugs in it. I've tried various descriptions of the A* algorithm and have redone this like 4 or 5 times with the same results... which suggests I'm missing something, but I can't figure out what it is. What is going on here? Using alternative heuristics like, e.g. diagonal (max of x/y distances) doesn't help it, though it's not curved anymore, it has either a long straight segment before diagonaling down (FIFO) or it diagonals down, then goes straight for a while, before a short diagonal up to the destination point (LIFO).