【问题标题】:Accurate A* search heuristic for isometric maps?等距地图的准确 A* 搜索启发式?
【发布时间】:2009-08-12 14:53:22
【问题描述】:

我已经编写了 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,反之亦然不会工作。

【问题讨论】:

  • 你说你正在寻找修复启发式;您可以发布与启发式相关的代码吗?或者有足够的代码让我们确定解决方案?
  • 您的启发式算法是基于像素的吗?曼哈顿距离是方形网格地图的典型距离,应该很容易转换为等距,因为无论如何您可能会将地图存储在方形矩阵中。无论如何,发布有关您当前的启发式方法如何工作以及如何在内部表示地图的提示将非常有帮助。我认为 CoderTao 的回答是正确的,但我也很困惑为什么他的建议需要完全重写。
  • 我的启发式方法不是基于像素的,我的地图也没有存储在方阵中,因此需要重写。如果是,则该地图将存储在方阵中,例如菱形。地图被投影为一个矩形。
  • 是的;但地图中的每个方格仍然是一组两个坐标。我们并不是建议对所有内容进行大规模重写。计算启发式时只需进行一些数据处理。最终,我们仍然需要一个更好的描述,以便能够更好地建议您采取什么课程。 (例如:我一直在谈论如何修复算法的完成部分的距离;在重读时,听起来你只是在“到达这里的距离”部分遇到了问题)
  • “到这里的距离”部分启发式的。而我需要的是一种能解释地图布局不规则性的启发式方法。

标签: algorithm search heuristics a-star isometric


【解决方案1】:

要尝试的一件事是将所有计算从等轴测坐标转换为方形网格坐标集。

假设 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));
}

更新基于新的问题:

假设您正在尝试获取 distance(3,2; 3,3)

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);
}

编辑:修正了可怕的错字......再次。

【讨论】:

  • 我需要修复启发式算法,而不是算法本身,这样做需要彻底改变系统。
  • 最终这只应该改变启发式;如果您尝试启发式剩余距离为 distance(squareCoords(current), squareCoords(dest));您不需要对系统进行任何其他更改。
  • 两件事:A)有一个错字 B)它没有给我比我目前的启发式更好的路径,有一个很好的理由:它没有考虑对角线运动
  • 我对糟糕的拼写不承担任何责任。那就是说;你是什​​么意思'它没有考虑对角线运动'?一个明确的例子来说明它在你身上所做的事情会很有用。
  • 它不会进行任何对角线移动,除非您正在移动到相邻的瓷砖。
【解决方案2】:

Amit 在这里计算“六边形的曼哈顿距离”。它的 C++ 代码,我无法保证,但 Amit 是我之前听说过的游戏开发名称。

六边形的曼哈顿距离应该适合适当的启发式。

编辑:颠倒了超链接的语法,哎呀。

【讨论】:

  • 很遗憾,六边形网格上的图块只能在 6 个方向上移动,而且每个方向的移动成本都是相等的,所以我不能用这个。
  • 天哪,我完全误读了你的问题。不知何故,等距变成了六角形。对此感到抱歉。
猜你喜欢
  • 2021-02-11
  • 1970-01-01
  • 2022-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多