Exemplo n.º 1
0
 public static Coordinate2D FindFirstEmpty(Level level)
 {
     foreach (Coordinate2D coord in level.InsideCoordinates)
     {
         if (level.IsEmpty(coord))
         {
             return coord;
         }
     }
     return Coordinate2D.Undefined;
 }
Exemplo n.º 2
0
        private void AddDisplacedBoxNoTarget(State state, Level level)
        {
            if (distance == 0)
            {
                AddRandomBox(state, level);
                return;
            }

            List<Coordinate2D> coordList = new List<Coordinate2D>();
            foreach (Coordinate2D coord in level.InsideCoordinates)
            {
                // Skip occupied coordinates.
                if (!level.IsEmpty(coord))
                {
                    continue;
                }

                // Find nearest target.
                int nearestTargetDistance = int.MaxValue;
                foreach (Coordinate2D targetCoord in level.TargetCoordinates)
                {
                    int targetDistance = Coordinate2D.GetDiagonalDistance(coord, targetCoord);
                    nearestTargetDistance = Math.Min(nearestTargetDistance, targetDistance);
                }

                // Check whether the nearest target is near enough.
                if (nearestTargetDistance <= (distance == 0 ? int.MaxValue : distance))
                {
                    coordList.Add(coord);
                }
            }
            if (coordList.Count == 0)
            {
                state.Log.DebugPrint("no available squares to add squares to");
                return;
            }
            Coordinate2D boxCoord = coordList[state.Random.Next(coordList.Count)];
            level[boxCoord] |= Cell.Box;
        }
Exemplo n.º 3
0
 private Coordinate2D GetRandomEmptySquare(State state, Level level)
 {
     List<Coordinate2D> coordList = new List<Coordinate2D>();
     foreach (Coordinate2D coord in level.InsideCoordinates)
     {
         if (level.IsEmpty(coord))
         {
             coordList.Add(coord);
         }
     }
     if (coordList.Count == 0)
     {
         return Coordinate2D.Undefined;
     }
     return coordList[state.Random.Next(coordList.Count)];
 }
Exemplo n.º 4
0
        private static Level TryNormalizeLoops(Level level)
        {
            // A loop is a tunnel that you cannot push a box through.
            // Any square that it is impossible or not useful to push
            // a box to is a no-box square.  All the squares in a loop
            // are no-box squares.  A level may have several disconnected
            // no-box regions.  Within one no-box region we can
            // optimize the path by removing islands that only
            // lengthen the loop without changing its function.
            // Finally, a normalized loop only needs to be one square
            // wide.

            // Copy the level and get island and no-box maps.
            bool modifiedLevel = false;
            Level newLevel = new Level(level);
            Array2D<bool> islandMap = LevelUtils.GetIslandMap(level);
            Array2D<int> noBoxMap = LevelUtils.GetNoBoxMap(level);

            // Any island that only contacts other walls and one or more
            // no-box squares in the same region can be removed.
            foreach (Coordinate2D coord in newLevel.Coordinates)
            {
                if (islandMap[coord])
                {
                    int wallCount = 0;
                    int noBoxCount = 0;
                    int region = 0;
                    foreach (Coordinate2D neighbor in coord.FourNeighbors)
                    {
                        if (newLevel.IsWall(neighbor))
                        {
                            wallCount++;
                        }
                        else if (noBoxMap[neighbor] != 0)
                        {
                            // Check whether we've encountered any no-box regions.
                            if (region == 0)
                            {
                                region = noBoxMap[neighbor];
                            }

                            // Only count no-box squares that match the first region.
                            if (noBoxMap[neighbor] == region)
                            {
                                noBoxCount++;
                            }
                        }
                    }
                    if (wallCount + noBoxCount == 4 && noBoxCount >= 1)
                    {
                        newLevel[coord] = Cell.Empty;
                        noBoxMap[coord] = 1;
                        islandMap[coord] = false;
                        modifiedLevel = true;
                    }
                }
            }

            // Make a map of all the inside squares we want to keep, initialized to false.
            Array2D<bool> keepMap = new Array2D<bool>(newLevel.Height, newLevel.Width);
            foreach (Coordinate2D coord in newLevel.InsideCoordinates)
            {
                if (noBoxMap[coord] != 0)
                {
                    // Keep all the no-box squares that contact box islands.
                    foreach (Coordinate2D neighbor in coord.EightNeighbors)
                    {
                        if (newLevel.IsValid(neighbor) && islandMap[neighbor])
                        {
                            keepMap[coord] = true;
                            break;
                        }
                    }

                    // Keep all the no-box squares that contact box squares.
                    foreach (Coordinate2D neighbor in coord.FourNeighbors)
                    {
                        if (newLevel.IsFloor(neighbor) && noBoxMap[neighbor] == 0)
                        {
                            keepMap[coord] = true;
                            break;
                        }
                    }
                }
                else
                {
                    // Keep all the box squares.
                    keepMap[coord] = true;
                }
            }

            // Fill in the no-box squares that we can safely remove.
            Coordinate2D sokobanCoord = newLevel.SokobanCoordinate;
            foreach (Coordinate2D coord in newLevel.InsideCoordinates)
            {
                if (!keepMap[coord])
                {
                    newLevel[coord] = Cell.Wall;
                    modifiedLevel = true;
                }
            }

            // If the sokoban was on one of the cells we didn't keep,
            // move it to a nearby box square.
            if (!newLevel.IsSokoban(sokobanCoord))
            {
                Level boxLevel = FillBoxSquaresWithBoxes(level, noBoxMap);
                PathFinder finder = PathFinder.CreateInstance(boxLevel);
                finder.Find(sokobanCoord);
                foreach (Coordinate2D coord in finder.AccessibleCoordinates)
                {
                    if (newLevel.IsEmpty(coord))
                    {
                        newLevel[coord] = Cell.Sokoban;
                        break;
                    }
                }
            }

            // Return the new level only if we made changes.
            if (modifiedLevel)
            {
                return newLevel;
            }

            return null;
        }
Exemplo n.º 5
0
 protected Exception Abort(string message)
 {
     string bugMessage = String.Format("bug: {0}", message);
     Log.DebugPrint(bugMessage);
     Level fullLevel = new Level(level);
     if (fullLevel.Sokobans == 0 && fullLevel.IsEmpty(current.SokobanRow, current.SokobanColumn))
     {
         fullLevel.AddSokoban(current.SokobanRow, current.SokobanColumn);
     }
     Log.DebugPrint(fullLevel.AsText);
     return new InvalidOperationException(bugMessage);
 }