Esempio n. 1
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);
        }
Esempio n. 2
0
        private void AddDisplacedBox(State state, Level level)
        {
            if (level.Targets > level.Boxes)
            {
                AddDisplacedBoxNoTarget(state, level);
                return;
            }

            Coordinate2D boxCoord = GetRandomJustFloorSquare(state, level);
            if (boxCoord.IsUndefined)
            {
                state.Log.DebugPrint("no available squares to add squares to");
                return;
            }
            level[boxCoord] = Cell.Box;
            int limit = distance == 0 ? int.MaxValue : distance;
            List<Coordinate2D> coordList = new List<Coordinate2D>();
            foreach (Coordinate2D coord in level.InsideCoordinates)
            {
                if (!level.IsTarget(coord))
                {
                    int targetDistance = Coordinate2D.GetDiagonalDistance(coord, boxCoord);
                    if (targetDistance <= limit)
                    {
                        coordList.Add(coord);
                    }
                }
            }
            if (coordList.Count == 0)
            {
                state.Log.DebugPrint("no available squares to add squares to");
                return;
            }
            Coordinate2D targetCoord = coordList[state.Random.Next(coordList.Count)];
            level[targetCoord] |= Cell.Target;
        }
Esempio n. 3
0
        private static void CheckForCapturedLine(Level level, Array2D<bool> simpleDeadlockMap,
            Coordinate2D coord, Coordinate2D perpendicular, Coordinate2D parallel)
        {
            // Check for straight walls that look like this:
            //     ###########
            //     #.->      #
            // where the dot is the starting position
            // and perpendicular is the direction of the wall
            // and parallel is the direction to search.

            if (!level.IsWall(coord - parallel))
            {
                return;
            }

            bool isCapturedLine = false;
            for (Coordinate2D c = coord; !level.IsTarget(c); c += parallel)
            {
                if (!level.IsWall(c + perpendicular))
                {
                    break;
                }
                if (level.IsWall(c + parallel))
                {
                    isCapturedLine = true;
                    break;
                }
            }

            if (!isCapturedLine)
            {
                return;
            }

            for (Coordinate2D c = coord; !level.IsWall(c); c += parallel)
            {
                simpleDeadlockMap[c] = true;
            }
        }
Esempio n. 4
0
        private static void CheckBox(Level level, Array2D<int> noBoxMap, Array2D<bool> simpleDeadlockMap, Coordinate2D coord)
        {
            // Check whether we've visited this square before.
            if (noBoxMap[coord] == 0)
            {
                return;
            }

            // This square is not a no-box square.
            noBoxMap[coord] = 0;

            // Recursively check for other squares that are not no-box squares.
            foreach (Direction direction in Direction.Directions)
            {
                // Get parallel and perpendicular offsets.
                Coordinate2D parallel = direction;
                Coordinate2D perpendicular = Coordinate2D.Transpose(parallel);

                // Check whether we can move the box to the new position.
                if (level.IsFloor(coord - parallel) && level.IsFloor(coord + parallel))
                {
                    Coordinate2D oldBoxCoord = coord;
                    Coordinate2D newBoxCoord = coord + parallel;

                    // Check for the special case of no influence pushes that lead to deadlocks.
                    bool specialCase = false;
                    while (level.IsWall(oldBoxCoord + perpendicular) &&
                        level.IsWall(oldBoxCoord - perpendicular) &&
                        ((level.IsWall(newBoxCoord + perpendicular) &&
                        level.IsWallOrEmpty(newBoxCoord - perpendicular)) ||
                        (level.IsWallOrEmpty(newBoxCoord + perpendicular) &&
                        level.IsWall(newBoxCoord - perpendicular))))
                    {
                        if (level.IsTarget(newBoxCoord))
                        {
                            break;
                        }
                        if (!level.IsFloor(newBoxCoord) || simpleDeadlockMap[newBoxCoord])
                        {
                            specialCase = true;
                            break;
                        }

                        oldBoxCoord += parallel;
                        newBoxCoord += parallel;
                    }

                    // Otherwise recursively check for more squares.
                    if (!specialCase)
                    {
                        CheckBox(level, noBoxMap, simpleDeadlockMap, coord + parallel);
                    }
                }
            }
        }
Esempio n. 5
0
        public static bool HasCapturedTargets(Level level)
        {
            // Get a captured map for the level without any targets.
            Array2D<bool> simpleDeadlockMap = DeadlockFinder.GetSimpleDeadlockMap(GetEmptyLevel(level));

            // Check for captured targets in the original level.
            foreach (Coordinate2D coord in level.Coordinates)
            {
                if (level.IsTarget(coord) && simpleDeadlockMap[coord])
                {
                    return true;
                }
            }
            return false;
        }
Esempio n. 6
0
        public static Array2D<bool> GetCapturedMap(Level level)
        {
            // Create a map of cell positions that if occupied correspond
            // to a deadlock.  This is similar to a simple deadlock map
            // but returns a different result if there are no targets.

            Array2D<bool> simpleDeadlockMap = new Array2D<bool>(level.Height, level.Width);

            foreach (Coordinate2D coord in level.InsideCoordinates)
            {
                if (level.IsTarget(coord))
                {
                    continue;
                }
                bool wallUp = level.IsWall(coord + Direction.Up);
                bool wallDown = level.IsWall(coord + Direction.Down);
                bool wallLeft = level.IsWall(coord + Direction.Left);
                bool wallRight = level.IsWall(coord + Direction.Right);
                if (wallUp && (wallLeft || wallRight))
                {
                    simpleDeadlockMap[coord] = true;
                    continue;
                }
                if (wallDown && (wallLeft || wallRight))
                {
                    simpleDeadlockMap[coord] = true;
                    continue;
                }
            }

            foreach (Coordinate2D coord in level.InsideCoordinates)
            {
                if (simpleDeadlockMap[coord])
                {
                    CheckForCapturedLine(level, simpleDeadlockMap, coord, Direction.Up, Direction.Right);
                    CheckForCapturedLine(level, simpleDeadlockMap, coord, Direction.Down, Direction.Right);
                    CheckForCapturedLine(level, simpleDeadlockMap, coord, Direction.Left, Direction.Down);
                    CheckForCapturedLine(level, simpleDeadlockMap, coord, Direction.Right, Direction.Down);
                }
            }

            return simpleDeadlockMap;
        }