C# 使用节点查找邻居/子节点/下一步移动,添加这些 继承人名单 浏览继任者列表,检查其中是否有任何一个包含目标状态, 否则添加到打开列表中 重复2-4,探索列表中的节点

C# 使用节点查找邻居/子节点/下一步移动,添加这些 继承人名单 浏览继任者列表,检查其中是否有任何一个包含目标状态, 否则添加到打开列表中 重复2-4,探索列表中的节点,c#,a-star,heuristics,sliding-tile-puzzle,C#,A Star,Heuristics,Sliding Tile Puzzle,当我用Q1尝试这些步骤时,我通过7个步骤得到了解决方案,这是正确的。这也是通过手工找到的。 但对于Q2,它会一直运行,直到开放列表为空,并且没有其他可供探索的内容。 那么,我缺少什么呢?我能够通过蛮力快速找到解决方案。如果你使用的是完全愚蠢的启发式,A*应该恢复为蛮力。您如何将您的状态与关闭状态列表进行比较 var set = new int[,] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 0 } }; var clone = (int[,])set.C

当我用Q1尝试这些步骤时,我通过7个步骤得到了解决方案,这是正确的。这也是通过手工找到的。 但对于Q2,它会一直运行,直到开放列表为空,并且没有其他可供探索的内容。
那么,我缺少什么呢?

我能够通过蛮力快速找到解决方案。如果你使用的是完全愚蠢的启发式,A*应该恢复为蛮力。您如何将您的状态与关闭状态列表进行比较

var set = new int[,] {
  { 1, 2, 3 },
  { 4, 5, 6 },
  { 7, 8, 0 }
};
var clone = (int[,])set.Clone();

var foo = clone == set; // foo is false
var bar = clone.Equals(set); // bar is false

var closedStates = new List<int[,]>();
closedStates.Contains(state); // wrong - contains is using Equals
closedStates.Any(cs => AreEqual(cs, state)); // correct

static bool AreEqual(int[,] stateA, int[,] stateB) {
  for (var x = 0; x < DIMENSIONS; x++) {
    for (var y = 0; y < DIMENSIONS; y++) {
      if (stateA[x, y] != stateB[x, y]) {
        return false;
      }
    }
  }
  return true;
}
var set=newint[,]{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 0 }
};
var clone=(int[,])set.clone();
var foo=clone==set;//福是假的
var bar=clone.Equals(set);//酒吧是假的
var closedStates=新列表();
closedStates.Contains(状态);//错误-contains使用的是Equals
closedStates.Any(cs=>arequal(cs,state));//对的
静态布尔值相等(int[,]状态A,int[,]状态B){
对于(变量x=0;x
我要感谢所有帮助我解决这个问题的人

我今天找到了问题。 我不知道怎么说,这真的很愚蠢。 问题不在于代码或A*实现(我当前的代码可能与之前发布的代码不同)

问题在于过度依赖使用的启发式方法。 似乎对于Q1,启发式h1、h2和h3(h1和h2的成本相同)都可以找到解决方案。 然而,对于Q2,h2和h3都无法找到通往溶液的路径,但h1是。 在我的程序中,我一直使用h3作为调试和测试的默认启发式,这也是我的失败之处

所以,我们应该吸取的教训是,要知道你们在做什么。 即使是最简单的启发式方法,我也无法意识到其中的差别

我现在可以解Q1和Q2了。 再次感谢大家。 作为一名程序员,我确实从中吸取了教训


我希望我能给你更多的荣誉,因为你花了时间来帮助我。

你有没有看过第四步的
openList
?为什么您的算法选择了“错误”的步骤?在这一点上,你的启发法说了什么?@MarcelB根据数字(启发法),它确实选择了最便宜的路线,但与其他程序(使用稍微不同的启发法)相比,它最终是错误的。你能为
GetBestNodeFromList(…)发布你的代码吗
?@MarcelB已添加到开场白中。您是否也可以添加“拼图”的代码?在最坏的情况下,A*应该恢复为蛮力(完全愚蠢的启发式)。如果你永远被困住,我的钱就在你身上,你正在访问已经关闭的州。我的州比较方法与你相同,但程序仍然无法找到第二季度的解决方案。另外,我在之前链接的维基百科文章中读到,解决一个8字难题的最大步骤数是31个步骤。当使用像A*这样的算法时,这也算数吗?或者,如果需要,它能走得更远吗?这是令人沮丧的,我不知道我的代码有什么问题>\uuu>顺便说一句,我使用的是曼哈顿启发法。@Mads M-你的代码中似乎有一些小错误;在没有完整来源的情况下悬停,很难说在哪里。例如,你在git上的某个地方有它吗?你可以从这个驱动器链接获取源代码,谢谢你的帮助。我就是不明白问题是什么,这问题困扰了我好几天。。
8 6 7
2 5 4
3 0 1
var openList = new List<int[,]> { current };
var closedList = new List<int[,]>();

while (openList.Count > 0)
{
    steps++;
    current = GetBestNodeFromList(correct, dimensions, openList, useHeuristic);
    // "GetBestNodeFromList()" finds the cheapest node in the openList.
    // cheapest node: lowest value of h3.

    openList.Remove(current);
    h1 = getHeuristic1b(current, correct, dimensions);
    h2 = getHeuristic2b(current, correct, dimensions);
    h3 = h1 + h2;
    if (h1 == 0 && h2 == 0) { break; }

    openList = Puzzle_PossibleNext(current, closedList);
    // the method "PossibleNext()" finds possible next moves from the current
    // position. if the next move exists in the closedList, it is discarded.

    // Drawing the puzzle and showing heuristics.
    DrawCurrentState(h1, h2, h3, current, steps);

    // adding last visited position to the closedlist.
    closedList.Add(current);
}
// Put heuristic value from all in list, then return list item with lowest h-value.
static int[,] GetBestNodeFromList(int[,] correct, int d, List<int[,]> list, string useHeuristic)
{
    int[,] n = new int[d,d];
    if (list.Count > 0)
    {
        List<Int32> heuristicsValueList = new List<Int32>();
        for (int i = 0; i < list.Count; i++)
        {
            if (useHeuristic == "h1")      { heuristicsValueList.Add(getHeuristic1b(list[i], correct, d)); }
            else if (useHeuristic == "h2") { heuristicsValueList.Add(getHeuristic2b(list[i], correct, d)); }
            else  { heuristicsValueList.Add(getHeuristic3(list[i], correct, d)); }
        }
        n = list[heuristicsValueList.IndexOf(heuristicsValueList.Min())];
    }
    return n;
}
static List<PuzzleNode> Puzzle_GenerateNextNodes(PuzzleNode node, List<PuzzleNode> closedNodeList)
        {
            List<PuzzleNode> nextList = new List<PuzzleNode>();
            Point isNow = new Point(0, 0);

            // 1) Find where [0] is.
            int dimensions = (int)Math.Sqrt((double)node.n.Length);
            for (int x = 0; x < dimensions; x++) {
                for (int y = 0; y < dimensions; y++) { if (node.n[x, y] == 0) { isNow.X = y; isNow.Y = x; break; } }
            }

            // 2) Check possible moves.
            bool moveUp = false, moveDown = false, moveLeft = false, moveRight = false;

            if (isNow.X == 0)
            {
                moveRight = true;
                if (isNow.Y == 0) { moveDown = true; }
                else if (isNow.Y == 1) { moveUp = true; moveDown = true; }
                else if (isNow.Y == 2) { moveUp = true; }
            }
            else if (isNow.X == 1)
            {
                moveRight = true;
                moveLeft = true;
                if (isNow.Y == 0) { moveDown = true; }
                else if (isNow.Y == 1) { moveUp = true; moveDown = true; }
                else if (isNow.Y == 2) { moveUp = true; }
            }
            else if (isNow.X == 2)
            {
                moveLeft = true;
                if (isNow.Y == 0) { moveDown = true; }
                else if (isNow.Y == 1) { moveUp = true; moveDown = true; }
                else if (isNow.Y == 2) { moveUp = true; }
            }
            // 3) Create list of possible moves.

// Add moved puzzle node to list over next moves 
            if (moveRight)
            {
                int[,] right = new int[dimensions, dimensions];
                Array.Copy(node.n, right, node.n.Length);
                PuzzleNode tmp = new PuzzleNode( PuzzleMoveRight(right, isNow.X, isNow.Y) );
                if (!ListHasThisValue(tmp.n, closedNodeList, dimensions)) { nextList.Add(tmp); }
            }
// moveleft, up, down, same structure as moveRight
            if (moveLeft)
            {
                ..
            }
            if (moveUp)
            {
                ..
            }
            if (moveDown)
            {
                ..
            }

            return nextList;
        }
var set = new int[,] {
  { 1, 2, 3 },
  { 4, 5, 6 },
  { 7, 8, 0 }
};
var clone = (int[,])set.Clone();

var foo = clone == set; // foo is false
var bar = clone.Equals(set); // bar is false

var closedStates = new List<int[,]>();
closedStates.Contains(state); // wrong - contains is using Equals
closedStates.Any(cs => AreEqual(cs, state)); // correct

static bool AreEqual(int[,] stateA, int[,] stateB) {
  for (var x = 0; x < DIMENSIONS; x++) {
    for (var y = 0; y < DIMENSIONS; y++) {
      if (stateA[x, y] != stateB[x, y]) {
        return false;
      }
    }
  }
  return true;
}