I implemented A* for the 8 puzzle problem pretty much word for word to the pseudo code in the wiki article but even though I have closed
I still get infinite runtime on boards that should fail.
It seems that the rate of opening new nodes is larger than closing them, since for each node about 1-4 new nodes are added to the open
but only one node is moved from open
to closed
.
So what can be done to recognize that a given starting board has no path to the goal without waiting forever?
This is the code:
public List<KeyValuePair<GameBoard, GameBoard.MoveDirection>> Search(GameBoard startBoard, GameBoard goal)
{
InitSearch(startBoard, goal);
while (_open.Count > 0)
{
GameBoard current = LowestFScoreInOpen();
if (current.Equals(_goal))
{
return ReconstructPath(current);
}
_open.Remove(current);
_closed.Add(current);
foreach (GameBoard.MoveDirection direction in Enum.GetValues(typeof(GameBoard.MoveDirection)))
{
GameBoard neighbor = current.MoveAndCopy(direction);
if(neighbor == null) continue; // invalid direction
if(_closed.Contains(neighbor)) continue;
int tentativeScore = _gScore[current] + 1;
if (!_open.Contains(neighbor))
{
_open.Add(neighbor);
}
else if (tentativeScore >= _gScore[neighbor])
{
continue; // already in _open and this is not a better path
}
// best path so far
_cameFrom[neighbor] = new KeyValuePair<GameBoard, GameBoard.MoveDirection>(current, direction);
_gScore[neighbor] = tentativeScore;
int fscore = tentativeScore + Heuristic(neighbor);
_fScore[neighbor] = fscore;
_sortedFScore.Enqueue(new PriorityQueueItem<GameBoard, int>(neighbor, fscore));
}
}
return null; // no path found
}
Example for start and goal board with no path between them:
Start: Goal:
Full code: https://pastebin.com/v10U2J2Z