Beispiel #1
0
 private HashKey GetPrintHashKey(Level level, PathFinder pathFinder)
 {
     if (solver.OptimizeMoves)
     {
         return level.GetOccupantsHashKey();
     }
     Coordinate2D sokobanCoord = level.SokobanCoordinate;
     pathFinder.Find();
     Coordinate2D proxySokobanCoord = pathFinder.GetFirstAccessibleCoordinate();
     level.MoveSokoban(proxySokobanCoord);
     HashKey hashKey = level.GetOccupantsHashKey();
     level.MoveSokoban(sokobanCoord);
     return hashKey;
 }
Beispiel #2
0
        public static Level Replace(Level level, int rowOffset, int columnOffset, Level replacement)
        {
            Level newLevel = new Level(level);
            bool lostSokoban = false;
            for (int row = 1; row < replacement.Height - 1; row++)
            {
                for (int column = 1; column < replacement.Width - 1; column++)
                {
                    if (replacement[row, column] != Cell.Undefined)
                    {
                        int rowTarget = row - 1 + rowOffset;
                        int columnTarget = column - 1 + columnOffset;
                        if (!level.IsValid(rowTarget, columnTarget))
                        {
                            return ExpandAndReplace(level, rowOffset, columnOffset, replacement);
                        }
                        if (level.IsSokoban(rowTarget, columnTarget) && !replacement.IsSokoban(row, column))
                        {
                            lostSokoban = true;
                        }
                        newLevel[rowTarget, columnTarget] = replacement[row, column];
                    }
                }
            }

            if (lostSokoban)
            {
                // Find an empty cell to relocate the sokoban to.
                foreach (Coordinate2D coord in replacement.Coordinates)
                {
                    if (replacement[coord] == Cell.Empty)
                    {
                        newLevel.MoveSokoban(coord.Row - 1 + rowOffset, coord.Column - 1 + columnOffset);
                        return newLevel;
                    }
                }
            }

            return newLevel;
        }
Beispiel #3
0
        private void AddLevel(State state, Level level, MoveList moveList)
        {
            // Optionally reject levels with dead-ends.
            if (rejectDeadEnds && LevelUtils.HasDeadEnds(level))
            {
                Reject(state, level, "level with dead ends");
                return;
            }

            // Optionally reject levels with captured targets.
            if (rejectCapturedTargets && LevelUtils.HasCapturedTargets(level))
            {
                Reject(state, level, "level with captured targets");
                return;
            }

            // Optionally move the sokoban away from the first box it pushes.
            MoveList finalMoveList = moveList;
            if (moveSokoban)
            {
                // Record old sokoban coordinate.
                Coordinate2D oldSokobanCoord = level.SokobanCoordinate;

                // Find accessible coordinates.
                PathFinder finder = PathFinder.CreateInstance(level);
                finder.Find();

                if (rejectSokobanOnTarget)
                {
                    // Move sokoban to first accessible non-target square.
                    foreach (Coordinate2D coord in finder.AccessibleCoordinates)
                    {
                        if (!level.IsTarget(coord))
                        {
                            level.MoveSokoban(coord);
                            break;
                        }
                    }
                    if (level.IsTarget(level.SokobanCoordinate))
                    {
                        Reject(state, level, "level with sokoban on target");
                        return;
                    }
                }
                else
                {
                    // Move sokoban to first accessible square.
                    foreach (Coordinate2D coord in finder.AccessibleCoordinates)
                    {
                        level.MoveSokoban(coord);
                        break;
                    }
                }

                // Solve one last time if the sokoban moved.
                if (oldSokobanCoord != level.SokobanCoordinate)
                {
                    finalMoveList = FinalSolve(state, level);
                    if (finalMoveList == null)
                    {
                        Reject(state, level, "final solver failed");
                        return;
                    }
                }
            }

            int moves = finalMoveList.Count;
            int pushes = LevelUtils.SolutionPushes(finalMoveList);
            int changes = LevelUtils.SolutionChanges(level, finalMoveList);
            int minBoxMoves = LevelUtils.MinimumBoxMoves(level, finalMoveList);

            // Add level to results.
            LevelInfo info = new LevelInfo();
            info.Level = level;
            info.Moves = moves;
            info.Pushes = pushes;
            info.Changes = changes;
            info.InsideSquares = level.InsideSquares;
            info.MinimumBoxMoves = minBoxMoves;
            info.MoveList = finalMoveList;

            AddResult(state, info);
        }
Beispiel #4
0
        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
        }