public static int SolutionChanges(Level level, MoveList solution) { if (solution == null) { return -1; } Level tempLevel = new Level(level); int changes = 0; int lastBoxIndex = -1; foreach (OperationDirectionPair pair in solution) { if (pair.Operation == Operation.Push) { int boxIndex = tempLevel.BoxIndex(tempLevel.SokobanCoordinate + pair.Direction); if (boxIndex != lastBoxIndex) { changes++; lastBoxIndex = boxIndex; } } tempLevel.Move(pair); } return changes; }
public static MoveList ShortenToFirstPush(Level level, MoveList moveList) { // Perform and count initial moves. int initialMoves = 0; foreach (OperationDirectionPair pair in moveList) { if (pair.Operation == Operation.Push) { break; } level.Move(pair); initialMoves++; } // Make a copy of the move list and shorten it. MoveList finalMoveList = new MoveList(moveList); finalMoveList.RemoveRange(0, initialMoves); return finalMoveList; }
public static int MinimumBoxMoves(Level level, MoveList solution) { if (solution == null) { return -1; } int boxes = level.Boxes; if (boxes == 0) { return 0; } int[] boxMoves = new int[boxes]; Level tempLevel = new Level(level); foreach (OperationDirectionPair pair in solution) { if (pair.Operation == Operation.Push) { boxMoves[tempLevel.BoxIndex(tempLevel.SokobanCoordinate + pair.Direction)]++; } tempLevel.Move(pair); } int min = int.MaxValue; foreach (int moves in boxMoves) { min = Math.Min(min, moves); } return min; }
public static bool IsSolutionCompatible(Level level, MoveList solution) { Level tempLevel = new Level(level); foreach (OperationDirectionPair pair in solution) { if (!tempLevel.Move(pair.Operation, pair.Direction)) { if (pair.Operation != Operation.Move || !tempLevel.Move(Operation.Push, pair.Direction)) { return false; } } } return true; }
public static Array2D<int> GetTraversalMap(Level level, MoveList solution) { // Create a traversal map counting the number of times // each square is occupied during the course of the solution, // initialized to zero. Array2D<int> traversalMap = new Array2D<int>(level.Height, level.Width); Level tempLevel = new Level(level); // Count the starting positions as one traversal. traversalMap[tempLevel.SokobanCoordinate]++; foreach (Coordinate2D coord in tempLevel.BoxCoordinates) { traversalMap[coord]++; } // Count all sokoban positions and box movements in the solution. foreach (OperationDirectionPair pair in solution) { if (pair.Operation == Operation.Push) { traversalMap[tempLevel.SokobanCoordinate + 2 * pair.Direction]++; } tempLevel.Move(pair); traversalMap[tempLevel.SokobanCoordinate]++; } return traversalMap; }
protected void CollectSolution(Node leaf) { foundSolution = true; // Don't bother if we're not collection solutions. if (!collectSolutions) { return; } // Prepare to construct the solution. MoveList solution = new MoveList(); Level tempLevel = new Level(originalLevel); tempLevel.Validate = validate; PathFinder tempFinder = PathFinder.CreateInstance(tempLevel, true); // Iterate over the nodes from the root to the leaf. int previousPushes = 0; #if false List<Node> nodeList = FindParents(root, leaf); #else List<Node> nodeList = new List<Node>(); for (int i = 0; i < current.ParentIndex; i++) { nodeList.Add(current.Parents[i]); } nodeList.Add(leaf); #endif foreach (Node node in nodeList) { // Check whether we need to move the sokoban. if (node.Coordinate != tempLevel.SokobanCoordinate) { // Move the sokoban to the box. solution.AddRange(tempFinder.FindAndGetPath(node.Coordinate)); tempLevel.MoveSokoban(node.Coordinate); } // Check whether we need to push a box. int consecutivePushes = node.Pushes - previousPushes; if (consecutivePushes != 0) { // Push the box one or more times. OperationDirectionPair push = new OperationDirectionPair(Levels.Operation.Push, node.Direction); for (int j = 0; j < consecutivePushes; j++) { solution.Add(push); tempLevel.Move(push); } previousPushes = node.Pushes; } } // Validate the solution. if (!tempLevel.IsComplete) { throw Abort("constructed move list does not solve level"); } if (optimizeMoves && solution.Count != leaf.Moves) { throw Abort("constructed move list does not match leaf tree in moves"); } if (LevelUtils.SolutionPushes(solution) != leaf.Pushes) { throw Abort("constructed move list does not match leaf tree in pushes"); } // Add the solution. solutions.Add(solution); int moves = solution.Count; int pushes = LevelUtils.SolutionPushes(solution); moveLimit = Math.Min(moveLimit, moves); pushLimit = Math.Min(pushLimit, pushes); #if DEBUG if (verbose) { Log.DebugPrint(" found solution: {0}/{1}", moves, pushes); } #endif }