我编写了A *搜索算法的实现。问题是我目前使用的启发式方法仅适用于方格网格。由于我的地图是等距的,启发式不会考虑实际地图的布局,因此也就是单元格之间的距离。
更新经过大量的记录和分析(读作花费大量时间试图找出平庸),我得出的结论是我当前的启发式工作原理很好,只有一个例外:最终结果与真实直线和对角线移动相反。
inline int Pathfinder::calculateDistanceEstimate(const CellCoord& coord) const
{
int diagonal = std::min(abs(coord.x-goal->position.x), abs(coord.y-goal->position.y));
int straight = (abs(coord.x-goal->position.x) + abs(coord.y-goal->position.y));
return 14 * diagonal + 10 * (straight - 2 * diagonal);
}
这意味着直接移动(实际上比等距地图上的对角线移动花费sqrt(2)
倍)计算为对角线移动。问题是:如何修改当前的启发式方法,以便为等轴测布局生成正确的结果?只需将diagonal
替换为straight
,反之亦然
答案 0 :(得分:4)
尝试的一件事是从等距坐标转换为所有计算的方形网格坐标集。
假设0,0保持地图的根。 0,1保持不变,1,2变为0.2; 1,3变为0,3; 2,3变为1,4; 3,3变为2,5; 0,2变为-1,1;这会使你回到正方形网格中,这样坐标和启发法就可以再次运作了。
Y坐标变为Y + sourceX偏移(3,3在x = 2;因此变为2,5);以数学方式找到sourceX证明自己更难。
[意识流;忽略] Y = 0处的等距坐标对于源X是准确的。因此,要计算源X,您需要'向左/向上移动Y次',这应该净化Y / 2的变化;向下舍入,在X坐标....大致建议方形坐标为:
sourceX = X - Y/2
sourceY = Y + sourceX
其中sourceX和sourceY是正常方形网格中的坐标;和Y / 2是整数运算/向下舍入。
所以,从理论上讲,这就变成了:
double DistanceToEnd(Point at, Point end)
{
Point squareStart = squarify(at);
Point squareEnd = squarify(end);
int dx=squareStart.X-squareEnd.X;
int dy=squareStart.Y-squareEnd.Y;
return Math.Sqrt(dx*dx+dy*dy);
}
Point squarify(Point p1)
{
return new Point(p1.X-p1.Y/2, p1.Y+(p1.X-p1.Y/2));
}
根据新问题点更新:
假设你试图获得距离(3,2; 3,3)< (距离(2,3; 3,3)=距离(3,1; 3,3));以下应该有效:(从C#翻译;不保证不存在的拼写错误)
inline int Pathfinder::calculateDistanceEstimate(const CellCoord& coord) const
{
int cx=coord.x - coord.y/2;
int cy=coord.y + cx;
int gx=goal->position.x - goal->position.y/2;
int gy=goal->position.y + gx;
int diagonal = std::min(abs(cx-gx), abs(cy-gy));
int straight = (abs(cx-gx) + abs(cy-gy));
return 14 * diagonal + 10 * (straight - 2 * diagonal);
}
编辑:修复了可怕的错字....再次。
答案 1 :(得分:-1)