C# 使用节点查找邻居/子节点/下一步移动,添加这些 继承人名单 浏览继任者列表,检查其中是否有任何一个包含目标状态, 否则添加到打开列表中 重复2-4,探索列表中的节点
当我用Q1尝试这些步骤时,我通过7个步骤得到了解决方案,这是正确的。这也是通过手工找到的。 但对于Q2,它会一直运行,直到开放列表为空,并且没有其他可供探索的内容。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
那么,我缺少什么呢?我能够通过蛮力快速找到解决方案。如果你使用的是完全愚蠢的启发式,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;
}