Beispiel #1
0
        /// <summary>
        /// Add the given square to the ordered list of uncertain squares.
        /// </summary>
        /// <param name="sqe"></param>
        private void AddUncertainSquare(MazeSquareExtension sqe, int behindPosition)
        {
            // Mark sqe's trajectoryDistance as uncertain.
            if (sqe.trajectoryDistance > 0)
            {
                sqe.trajectoryDistance *= -1;
            }

            AddSquare(sqe, behindPosition, uncertainSquares);
        }
Beispiel #2
0
        /// <summary>
        /// Add the given square to the ordered list of uncertain squares.
        /// </summary>
        /// <param name="sqe"></param>
        private void AddConfirmedSquare(MazeSquareExtension sqe, int behindPosition)
        {
            // Mark sqe's trajectoryDistance as confirmed.
            if (sqe.trajectoryDistance < 0)
            {
                sqe.trajectoryDistance *= -1;
            }

            AddSquare(sqe, behindPosition, confirmedSquares);
        }
Beispiel #3
0
        /// <summary>
        /// Update the lowestRelativesPenalty member variable.
        /// Consider all squares in the list of open paths.
        /// </summary>
        private void UpdateLowestPenalty()
        {
            this.lowestRelativesPenalty = double.MaxValue;

            foreach (MazeSquare sq in list)
            {
                MazeSquareExtension sqe = mazeExtension[sq.XPos, sq.YPos];
                lowestRelativesPenalty = Math.Min(lowestRelativesPenalty, sqe.deadRelativesPenalty);
            }
        }
Beispiel #4
0
        /// <summary>
        /// Initialize trajectoryDistance of all squares in the mazeExtension.
        /// </summary>
        /// <param name="maze"></param>
        private void InitializeTrajectoryDistances(Maze maze)
        {
            List <MazeSquareExtension> list = new List <MazeSquareExtension>();

            InitializeEndpoints(maze, list);

            while (list.Count > 0)
            {
                // Take the first item from the list.
                MazeSquareExtension sqe1 = list[0];
                list.RemoveAt(0);

                if (sqe1.trajectoryDistance <= 0)
                {
                    for (int i = 0; i < sqe1.neighbors.Count; i++)
                    {
                        MazeSquareExtension sqe2 = sqe1.neighbors[i];

                        // Set the potential (negative) trajectory distance:
                        //  * sqe2's distance is one greater than sqe1's
                        //  * but only if this is better than the current potential
                        if (sqe1.trajectoryDistance - 1 > sqe2.trajectoryDistance && !sqe2.isDeadEnd)
                        // && sqe2.trajectoryDistance < 0 --
                        {
                            // When first encountered: add sqe2 to the list.
                            if (sqe2.trajectoryDistance == int.MinValue)
                            {
                                list.Add(sqe2);
                                sqe2.trajectoryDistance = sqe1.trajectoryDistance - 1;
                            }
                            else
                            {
                                sqe2.trajectoryDistance = sqe1.trajectoryDistance - 1;
                                list.Remove(sqe2);
                                #region Find a new position p in the list
                                int p;
                                for (p = 0; p < list.Count; p++)
                                {
                                    // The potential distance must be at least as good...
                                    if (sqe2.trajectoryDistance >= list[p].trajectoryDistance)
                                    {
                                        break;
                                    }
                                }
                                #endregion
                                list.Insert(p, sqe2);
                            }
                        }
                    }

                    // Convert a potential distance to an actual distance.
                    sqe1.trajectoryDistance *= -1;
                }
            }
        }
Beispiel #5
0
 /// <summary>
 /// All neighbors whose current (incertain) trajectory is supported by the given (confirmed) square
 /// are also confirmed.
 /// (That is the case if their distances differ by 1.
 /// </summary>
 /// <param name="sqe"></param>
 private void ReviveUncertainNeighbors(MazeSquareExtension sqe)
 {
     for (int i = 0; i < sqe.neighbors.Count; i++)
     {
         MazeSquareExtension sqe2 = sqe.neighbors[i];
         if (-sqe2.trajectoryDistance == sqe.trajectoryDistance + 1 && !sqe2.isDeadEnd)
         {
             AddConfirmedSquare(sqe2, -1);
             ReviveUncertainNeighbors(sqe2);
         }
     }
 }
Beispiel #6
0
        private void InitializeEndpoints(Maze maze, List <MazeSquareExtension> endSquares)
        {
            // Mark start square as visited.
            MazeSquareExtension sqeStart = mazeExtension[maze.StartSquare.XPos, maze.StartSquare.YPos];

            sqeStart.isDeadEnd          = true;
            sqeStart.trajectoryDistance = -1;

            // Add end square to the list.
            MazeSquareExtension sqeEnd = mazeExtension[maze.EndSquare.XPos, maze.EndSquare.YPos];

            sqeEnd.trajectoryDistance = 0;
            endSquares.Add(sqeEnd);
        }
Beispiel #7
0
        /// <summary>
        /// Adjust trajectory distances of the uncertainSquares.
        /// </summary>
        private void CollectUncertainSquares()
        {
            // Note: Initially, uncertainSquares is an ordered list of the neighbors of a visited square.
            //       As our search for a new trajectory continues, more squares will be marked uncertain
            //       and added to this list.  The sort order will be preserved.

            for (int i = 0; i < uncertainSquares.Count; i++)
            {
                MazeSquareExtension sqe1 = uncertainSquares[i];

                if (sqe1.trajectoryDistance > 0)
                {
                    // This square's trajectory has been confirmed.  It is not uncertain any more.
                    continue;
                }

                if (sqe1.isDeadEnd)
                {
                    // No chance to revive an already dead square!
                    continue;
                }

                // We need to find a neighbor that gives this square a new trajectory.
                int requiredNeighborDistance = -sqe1.trajectoryDistance - 1;

                for (int j = 0; j < sqe1.neighbors.Count; j++)
                {
                    MazeSquareExtension sqe2 = sqe1.neighbors[j];

                    if (sqe2.trajectoryDistance == requiredNeighborDistance)
                    {
                        // We have confirmed that sqe1 has a neighbor sqe2 giving it a new trajectory.
                        AddConfirmedSquare(sqe1, -1);

                        // Immediately revive any neighbors supported by sqe1.
                        ReviveUncertainNeighbors(sqe1);

                        break; // from for (j)
                    }
                    else if (sqe2.trajectoryDistance > requiredNeighborDistance)
                    {
                        // Add this square to the list of uncertainSquares.
                        AddUncertainSquare(sqe2, i);
                    }
                }
            }
        }
Beispiel #8
0
        /// <summary>
        /// Create a DeadEndChecker, based on the given Maze.
        /// </summary>
        /// <param name="maze"></param>
        public DeadEndChecker(Maze maze)
        {
            this.mazeExtension = new MazeSquareExtension[maze.XSize, maze.YSize];
            #region Create mazeExtension[i, j]
            for (int i = 0; i < maze.XSize; i++)
            {
                for (int j = 0; j < maze.YSize; j++)
                {
                    mazeExtension[i, j] = new MazeSquareExtension();
                }
            }
            #endregion

            // Set up the mazeExtension
            InitializeMazeExtension(maze);
            InitializeTrajectoryDistances(maze);
        }
Beispiel #9
0
        /// <summary>
        /// Assign valid (positve) trajectory distances to all uncertain neighbors of the confirmedSquares.
        /// </summary>
        private void ReviveConfirmedSquaresNeighbors()
        {
            // Note: The confirmedSquares list is ordered by increasing trajectoryDistance.
            //       Additional items will be added while we traverse the adjoining area.

            for (int i = 0; i < confirmedSquares.Count; i++)
            {
                MazeSquareExtension sqe1 = confirmedSquares[i];
                for (int j = 0; j < sqe1.neighbors.Count; j++)
                {
                    MazeSquareExtension sqe2 = sqe1.neighbors[j];
                    if (sqe2.trajectoryDistance < 0 && !sqe2.isDeadEnd)
                    {
                        sqe2.distanceChanged    = (-sqe2.trajectoryDistance != sqe1.trajectoryDistance + 1);
                        sqe2.trajectoryDistance = sqe1.trajectoryDistance + 1;
                        AddConfirmedSquare(sqe2, i);
                    }
                }
            }
        }
Beispiel #10
0
        /// <summary>
        /// Initialize all squares in the mazeExtension (everything but trajectoryDistance).
        /// </summary>
        /// <param name="maze"></param>
        private void InitializeMazeExtension(Maze maze)
        {
            for (int i = 0; i < maze.XSize; i++)
            {
                for (int j = 0; j < maze.YSize; j++)
                {
                    MazeSquare          sq  = maze[i, j];
                    MazeSquareExtension sqe = mazeExtension[i, j];

                    // extendedSquare:
                    sqe.extendedSquare = sq;

                    if (sq.isReserved)
                    {
                        // isDeadEnd:
                        sqe.isDeadEnd          = true;
                        sqe.trajectoryDistance = -1;
                    }
                    else
                    {
                        // neighbors:
                        sqe.neighbors = new List <MazeSquareExtension>(4);

                        for (WallPosition wp = WallPosition.WP_MIN; wp <= WallPosition.WP_MAX; wp++)
                        {
                            MazeSquare sq2 = sq.NeighborSquare(wp);

                            if (sq2 != null && !sq2.isReserved)
                            {
                                sqe.neighbors.Add(mazeExtension[sq2.XPos, sq2.YPos]);
                            }
                        }

                        // Negative values mean: not initialized
                        sqe.trajectoryDistance = int.MinValue;
                    }
                }
            }
        }
Beispiel #11
0
        /// <summary>
        /// Returns true if no squares could have possibly been killed by visiting the given square.
        /// </summary>
        /// <param name="sqe"></param>
        /// <returns></returns>
        ///
        /// +---+---+---+   +---+---+---+
        /// |   |   |   |   |   | o | x |   In these diagrams, sqe is the center square.
        /// +---+---+---+   +---+---+---+   "x" are dead squares; "o" are alive squares; the rest is irrelevant
        /// | x | x | x |   | x | x | o |   These two constellations are critical (not harmless).
        /// +---+---+---+   +---+---+---+
        /// |   |   |   |   |   |   |   |   The straight constellation is harmless if one of the parallel lines
        /// +---+---+---+   +---+---+---+   is completely dead.
        ///
        private bool HarmlessConstellation(MazeSquareExtension sqe)
        {
            int x = sqe.extendedSquare.XPos, y = sqe.extendedSquare.YPos;
            int w = mazeExtension.GetUpperBound(0);
            int h = mazeExtension.GetUpperBound(1);

            #region Identify straight lines.

            bool deadW = (x == 0 || mazeExtension[x - 1, y].isDeadEnd);
            bool deadE = (x == w || mazeExtension[x + 1, y].isDeadEnd);
            bool deadN = (y == 0 || mazeExtension[x, y - 1].isDeadEnd);
            bool deadS = (y == h || mazeExtension[x, y + 1].isDeadEnd);

            bool deadNW = (x == 0 || y == 0 || mazeExtension[x - 1, y - 1].isDeadEnd);
            bool deadNE = (x == w || y == 0 || mazeExtension[x + 1, y - 1].isDeadEnd);
            bool deadSW = (x == 0 || y == h || mazeExtension[x - 1, y + 1].isDeadEnd);
            bool deadSE = (x == w || y == h || mazeExtension[x + 1, y + 1].isDeadEnd);

            if (deadW && deadE)
            {
                if (deadN || deadS)
                {
                    return(true);
                }
                return(false);
            }

            if (deadN && deadS)
            {
                if (deadW || deadE)
                {
                    return(true);
                }
                return(false);
            }

            #endregion

            #region Identify angled lines.

            if (deadNW && !deadN && !deadW && (deadS || deadE))
            {
                return(false);
            }

            if (deadNE && !deadN && !deadE && (deadS || deadW))
            {
                return(false);
            }

            if (deadSW && !deadS && !deadW && (deadN || deadE))
            {
                return(false);
            }

            if (deadSE && !deadS && !deadE && (deadN || deadW))
            {
                return(false);
            }

            #endregion

            return(true);
        }
Beispiel #12
0
        private void AddSquare(MazeSquareExtension sqe, int behindPosition, List <MazeSquareExtension> list)
        {
            if (list.Count > 8 * mazeExtension.Length)
            {
                throw new Exception("internal list grows too long");
            }

            int key = sqe.trajectoryDistance; if (key < 0)
            {
                key = -key;
            }

            // The key needs to be compared with the squares in the index range a..b
            int a = behindPosition + 1, b = list.Count - 1;

            // Empty region.
            if (b < a)
            {
                list.Add(sqe);
                return;
            }

            int keyA = list[a].trajectoryDistance; if (keyA < 0)
            {
                keyA = -keyA;
            }
            int keyB = list[b].trajectoryDistance; if (keyB < 0)

            {
                keyB = -keyB;
            }

            // The square fits at the end of the list.
            if (keyB <= key)
            {
                list.Add(sqe);
                return;
            }

            // The square fits at the start of the list.
            if (keyA >= key)
            {
                list.Insert(a, sqe);
                return;
            }

            // Find a position for insertion into the list.
            // keyA < key < keyB
            while (a < b)
            {
                int m    = (a + b) / 2;
                int keyM = list[m].trajectoryDistance; if (keyM < 0)
                {
                    keyM = -keyM;
                }

                if (keyM > key)
                {
                    b = m;
                }
                else if (keyM < key)
                {
                    a = m + 1;
                }
                else
                {
                    a = m + 1;
                    break;
                }
            }

            list.Insert(a, sqe);
        }
Beispiel #13
0
        /// <summary>
        /// Registers the given square as visited.
        /// </summary>
        /// <param name="sq"></param>
        /// <returns>a list of dead end squares</returns>
        public List <MazeSquare> Visit(MazeSquare sq)
        {
            List <MazeSquare>   result = new List <MazeSquare>();
            MazeSquareExtension sqe    = mazeExtension[sq.XPos, sq.YPos];

            // Don't process squares that have been visited before.
            if (sqe.isDeadEnd)
            {
                return(result);
            }

            // The visited square is marked as dead.
            sqe.isDeadEnd = true;
            int d = sqe.trajectoryDistance;

            if (d > 0)
            {
                sqe.trajectoryDistance *= -1;
            }
            else
            {
                d *= -1;
            }

            if (d == 0)
            {
                // This is the end square.  No need to kill any more squares...
                return(result);
            }

            // Add neighbors to the list of uncertainSquares if their trajectory passed through the visited square.
            // That is the case if their distance is greater by one than the visited square's distance.
            for (int i = 0; i < sqe.neighbors.Count; i++)
            {
                MazeSquareExtension sqe2 = sqe.neighbors[i];

                if (sqe2.trajectoryDistance == d + 1)
                {
                    AddUncertainSquare(sqe2, -1);
                }
            }

            if (HarmlessConstellation(sqe))
            {
                return(result);
            }

            // Add all squares whose trajectory depends on the ones already inserted.
            CollectUncertainSquares();

            // The areas next to all confirmedSquares will receive an adjusted trajectoryDistance.
            ReviveConfirmedSquaresNeighbors();

            // The remaining uncertainSquares with negative (invalid) trajectoryDistance are dead.
            for (int j = 0; j < uncertainSquares.Count; j++)
            {
                MazeSquareExtension sqe2 = uncertainSquares[j];
                if (sqe2.trajectoryDistance < 0 && !sqe2.isDeadEnd)
                {
                    sqe2.isDeadEnd = true;
                    if (sqe2.extendedSquare.MazeId == sq.MazeId)
                    {
                        result.Add(sqe2.extendedSquare);
                    }
                }
            }

            // Empty the internal lists.
            uncertainSquares.Clear();
            confirmedSquares.Clear();

            return(result);
        }