protected override void SearchTree(Node node, int depth) { // If the root hasn't been searched yet, manually expand it. if (!node.Searched) { MoveState state = new MoveState(); node.Searched = true; HashKey hashKey = current.HashKey; bool result = IsTerminal(ref state, node) || !FindChildren(node); current.HashKey = hashKey; } int lastNodeCount = nodes.Visited; Search(node); if (verbose) { string searching = foundSolution ? "Post-searching" : "Searching"; string info = String.Format("{0} to depth {1},\r\n", searching, depth); info += String.Format("Examined {0:#,##0} new nodes ({1:#,##0} total)...", nodes.Visited - lastNodeCount, nodes.Visited); info += String.Format("\r\nNodes allocated {0:#,##0}\r\n", nodes.Allocated); SetInfo(info); } }
private void Search(Node node) { // Check for cancel. if (cancelInfo.Cancel) { return; } MoveState state = new MoveState(); state.PrepareToMove(node, ref current); int score = Node.MaxScore; Node previous = node; for (Node child = node.Child; !Node.IsEmpty(child); child = child.Sibling) { if (child.Terminal) { // Another node displaced this node from the transposition table. RemoveDescendants(child); RemoveScore(child); node.Remove(previous, child); nodes.Release(child); continue; } if (child.Score > scoreLimit) { if (child.Score < score) { score = child.Score; } previous = child; continue; } state.DoMove(child, ref current); if (child.Searched) { Search(child); if (!child.HasChildren) { node.Remove(previous, child); RemoveScore(child); if (child.InTable) { child.Dormant = true; } else { nodes.Release(child); } goto removed; } } else { // Remove the unsearched score. #if false int oldScore = child.Score; #endif RemoveScore(child); // Search the child node. child.Searched = true; if (level.IsComplete) { child.Complete = true; CollectSolution(child); node.Remove(previous, child); child.Dormant = true; RemoveScore(child); goto removed; } if (IsTerminal(ref state, child) || !FindChildren(child)) { node.Remove(previous, child); if (child.InTable) { // Node had no children so it is effectively deadlocked. transpositionTable[current.HashKey] = Node.Empty; } RemoveScore(child); nodes.Release(child); goto removed; } #if false // XXX: This works but doesn't seem to help. if (child.Score == oldScore) { Search(child); if (!child.HasChildren) { node.Remove(nodes, previous, child); RemoveScore(child); if (child.InTable) { child.Dormant = true; } else { child.Release(nodes); } goto removed; } } #endif } if (child.Score < score) { score = child.Score; } previous = child; removed: state.UndoMove(ref current); } SetScore(node, score); state.FinishMoving(ref current); }
protected override void SearchTree(Node node, int depth) { // If the root hasn't been searched yet, manually expand it. if (!node.Searched) { MoveState state = new MoveState(); node.Searched = true; HashKey hashKey = current.HashKey; bool result = IsTerminal(ref state, node) || !FindChildren(node); current.HashKey = hashKey; } if (foundSolution && !optimizeMoves/* && !optimizePushes */) { return; } // Check for cancel. string info = null; int lastNodeCount = nodes.Visited; while (!cancelInfo.Cancel) { if (root.Score == Node.MaxScore) { return; } CalculateScoreLimit(); if (scoreTotal == 0) { break; } if (verbose) { string searching = foundSolution ? "Post-searching" : "Searching"; info = String.Format("{0} with root score {1} and score limit {2},\r\n", searching, root.Score, scoreLimit); } int n = nodes.Visited; Search(node); if (verbose) { info += String.Format("Examined {0:#,##0} new nodes ({1:#,##0} total)...", nodes.Visited - lastNodeCount, nodes.Visited); info += String.Format("\r\nNodes allocated {0:#,##0}\r\n", nodes.Allocated); info += String.Format("Best lower bound: {0}, best level:\r\n{1}", bestLowerBound, bestLevel.AsText); SetInfo(info); } if (nodes.Visited > n) { break; } } }
private void PrintTreeWithLevels(Node node, Level level, PathFinder pathFinder) { Print(node); HashKey hashKey = GetPrintHashKey(level, pathFinder); if (transpositionTable.ContainsKey(hashKey)) { Node other = transpositionTable[hashKey]; Log.DebugPrint("table node: {0}", Node.IsEmpty(other) ? -1 : other.ID); } else { Log.DebugPrint("not in table"); } Print(level); MoveState state = new MoveState(); state.PrepareToMove(node, ref current); foreach (Node child in node.Children) { state.DoMove(child, ref current); PrintTreeWithLevels(child, level, pathFinder); state.UndoMove(ref current); } state.FinishMoving(ref current); }
private void Search(Node node) { // Check for cancel. if (cancelInfo.Cancel) { return; } MoveState state = new MoveState(); state.PrepareToMove(node, ref current); Node previous = node; for (Node child = node.Child; !Node.IsEmpty(child); child = child.Sibling) { if (child.Terminal) { // Another node displaced this node from the transposition table. RemoveDescendants(child); node.Remove(previous, child); nodes.Release(child); continue; } state.DoMove(child, ref current); if (child.Searched) { Search(child); if (!child.HasChildren) { node.Remove(previous, child); if (child.InTable) { child.Dormant = true; } else { nodes.Release(child); } goto removed; } } else { // Search the child node. child.Searched = true; if (level.IsComplete) { child.Complete = true; CollectSolution(child); node.Remove(previous, child); child.Dormant = true; goto removed; } if (IsTerminal(ref state, child) || !FindChildren(child)) { node.Remove(previous, child); if (child.InTable) { // Node had no children so it is effectively deadlocked. transpositionTable[current.HashKey] = Node.Empty; } nodes.Release(child); goto removed; } } previous = child; removed: state.UndoMove(ref current); } state.FinishMoving(ref current); }
protected bool IsTerminalWithoutMoves(ref MoveState state, Node node) { // Update current hash key for node. #if USE_INCREMENTAL_PATH_FINDER state.Find(ref current); #else pathFinder.Find(current.SokobanRow, current.SokobanColumn); #endif #if USE_INCREMENTAL_HASH_KEY Coordinate2D proxySokobanCoord = pathFinder.GetFirstAccessibleCoordinate(); current.HashKey ^= HashKey.GetSokobanHashKey(proxySokobanCoord.Row, proxySokobanCoord.Column); #else current.HashKey = GetSlowHashKey(); #endif #if DEBUG ValidateHashKey(node); #endif // Look up the current hash key in the transposition table. Node other; if (transpositionTable.TryGetValue(current.HashKey, out other)) { duplicates++; // Choose which node to pursue. if (Node.IsEmpty(other) || other.Pushes <= node.Pushes) { // The other node is deadlocked or as good as this one. return true; } // This node is better than the other one, which is not deadlocked. transpositionTable[current.HashKey] = node; node.InTable = true; other.InTable = false; if (other.Dormant) { nodes.Release(other); } else { other.Terminal = true; } #if DEBUG ValidateNotDeadlocked(); #endif return false; } if (deadlockFinder.IsDeadlocked(current.SokobanRow, current.SokobanColumn)) { transpositionTable.Add(current.HashKey, Node.Empty); return true; } transpositionTable.Add(current.HashKey, node); node.InTable = true; return false; }
protected bool IsTerminalWithMoves(ref MoveState state, Node node) { // Update current hash key for node. #if USE_INCREMENTAL_HASH_KEY current.HashKey ^= HashKey.GetSokobanHashKey(current.SokobanRow, current.SokobanColumn); #else current.HashKey = GetSlowHashKey(); #endif #if DEBUG ValidateHashKey(node); #endif // Look up the current hash key in the transposition table. Node other; if (transpositionTable.TryGetValue(current.HashKey, out other)) { duplicates++; // Choose which node to pursue. if (optimizePushes) { if (Node.IsEmpty(other) || other.Pushes < node.Pushes || other.Pushes == node.Pushes && other.Moves <= node.Moves) { // The other node is deadlocked or as good as than this one. return true; } } else { if (Node.IsEmpty(other) || other.Moves <= node.Moves) { // The other node is deadlocked or as good as than this one. return true; } } // This node is better than the other one, which is not deadlocked. transpositionTable[current.HashKey] = node; node.InTable = true; other.InTable = false; if (other.Dormant) { nodes.Release(other); } else { other.Terminal = true; } // This is no longer a duplicate and not deadlocked, so run the finder. #if USE_INCREMENTAL_PATH_FINDER state.Find(ref current); #else pathFinder.Find(current.SokobanRow, current.SokobanColumn); #endif #if DEBUG ValidateNotDeadlocked(); #endif return false; } if (deadlockFinder.IsDeadlocked(current.SokobanRow, current.SokobanColumn)) { transpositionTable.Add(current.HashKey, Node.Empty); return true; } // This is a brand new position, so record it. transpositionTable.Add(current.HashKey, node); node.InTable = true; // This is not a duplicate and not deadlocked, so run the finder. #if USE_INCREMENTAL_PATH_FINDER state.Find(ref current); #else pathFinder.Find(current.SokobanRow, current.SokobanColumn); #endif return false; }
protected bool IsTerminal(ref MoveState state, Node node) { // This method performs four tasks: // - computes the hash key for the node // - determines whether this node is a duplicate of another in the transposition table // - determines whether this node is deadlocked // - determines which squares are accessible from this node // The optimal order of the tasks depends on the situation for maximum efficiency. return optimizeMoves ? IsTerminalWithMoves(ref state, node) : IsTerminalWithoutMoves(ref state, node); }