Beispiel #1
0
        /// <summary>
        /// Travel from one visited square to a neighbor square (through an open wall).
        /// </summary>
        /// <param name="sq1">first (previously visited) square</param>
        /// <param name="sq2">next (neighbor) square</param>
        /// <param name="forward">true if the neighbor square was not visited previously</param>
        protected override void StepI(out MazeSquare sq1, out MazeSquare sq2, out bool forward)
        {
            if (maze.IsSolved)
            {
                throw new Exception("Maze is already solved.");
            }

            // Get the current square.
            sq1 = stack.Peek();

            // Possible choices of open walls (not visited).
            List <WallPosition> openWalls = OpenWalls(sq1, true);

            if (openWalls.Count > 0)
            {
                // Select one of the neighbor squares.
                WallPosition wp = SelectDirection(sq1, openWalls);

                sq2     = sq1.NeighborSquare(wp);
                forward = true;

                // Push the next square onto the stack.
                stack.Push(sq2);
                sq2.isVisited = true;
            }
            else
            {
                // Pop the current square from the stack.
                stack.Pop();

                sq2     = stack.Peek();
                forward = false;
            }
        }
Beispiel #2
0
        /// <summary>
        /// Returns a list of directions leading from the given square to neighbors through open walls.
        /// Neighbors that have been identified as dead ends are excluded (efficient solvers only).
        /// </summary>
        /// <param name="sq"></param>
        /// <param name="notVisitedOnly">
        /// When true: Exclude neighbors that have already been visited.
        /// </param>
        /// <returns></returns>
        protected List <WallPosition> OpenWalls(MazeSquare sq, bool notVisitedOnly)
        {
            List <WallPosition> result = new List <WallPosition>((int)WallPosition.WP_NUM);

            for (WallPosition wp = WallPosition.WP_MIN; wp <= WallPosition.WP_MAX; wp++)
            {
                if (sq[wp] == WallState.WS_OPEN)
                {
                    MazeSquare sq2 = sq.NeighborSquare(wp);

                    if (notVisitedOnly)
                    {
                        // Exclude squares that have already been visited.
                        if (sq2.isVisited)
                        {
                            continue;
                        }
                    }

                    // Exclude squares that need not be visited because they are dead ends.
                    if (this.deadEndChecker != null && deadEndChecker.IsDead(sq2))
                    {
                        continue;
                    }

                    result.Add(wp);
                }
            }

            return(result);
        }
Beispiel #3
0
        /// <summary>
        /// Check if a move to the neighbor square in the current direction would be valid.
        /// </summary>
        /// <returns>true if the move is invalid</returns>
        protected virtual bool CurrentDirectionIsInvalid()
        {
            // Check for open/closed walls.
            if (currentSquare[currentDirection] != WallState.WS_OPEN)
            {
                return(true);
            }

            // Check for dead ends.
            if (deadEndChecker != null)
            {
                MazeSquare sq = currentSquare.NeighborSquare(currentDirection);

                if (sq.isVisited)
                {
                    // Backward moves must be respected.
                    return(false);
                }

                if (deadEndChecker.IsDead(sq))
                {
                    return(true);
                }
            }

            // No problem.
            return(false);
        }
        private static List <MazeSquare> Move(DeadEndChecker target, ref MazeSquare sq, WallPosition direction, int expectedDeadSquaresCount)
        {
            sq = sq.NeighborSquare(direction);
            List <MazeSquare> deadSquares = target.Visit(sq);

            Assert.AreEqual(expectedDeadSquaresCount, deadSquares.Count, "Number of dead squares doesn't match.");
            return(deadSquares);
        }
Beispiel #5
0
        /// <summary>
        /// Add the given penalty to the given square and all already visited paths beyond.
        /// </summary>
        /// <param name="sq"></param>
        /// <param name="penalty"></param>
        private void AddDeadBranchPenalty(MazeSquare sq, double penalty)
        {
            mazeExtension[sq.XPos, sq.YPos].deadRelativesPenalty += penalty;

            foreach (WallPosition wp in OpenWalls(sq, false))
            {
                MazeSquare sq2 = sq.NeighborSquare(wp);
                if (sq2.isVisited && sq2 != mazeExtension[sq.XPos, sq.YPos].previousSquare)
                {
                    AddDeadBranchPenalty(sq2, penalty);
                }
            }
        }
        /// <summary>
        /// Select one of the open walls leading away from the given square.
        /// </summary>
        /// <param name="sq1"></param>
        /// <param name="openWalls"></param>
        /// <returns></returns>
        protected override WallPosition SelectDirection(MazeSquare sq1, List <WallPosition> openWalls)
        {
            int    bestIdx      = 0;
            double bestDistance = double.MaxValue;

            for (int i = 0; i < openWalls.Count; i++)
            {
                double distance = Maze.Distance(referenceSquare, sq1.NeighborSquare(openWalls[i]));
                if (distance < bestDistance)
                {
                    bestIdx      = i;
                    bestDistance = distance;
                }
            }

            return(openWalls[bestIdx]);
        }
Beispiel #7
0
        /// <summary>
        /// Travel from one visited square to a neighbor square (through an open wall).
        /// </summary>
        /// <param name="sq1">first (previously visited) square</param>
        /// <param name="sq2">next (neighbor) square</param>
        /// <param name="forward">true if the neighbor square was not visited previously</param>
        protected override void StepI(out MazeSquare sq1, out MazeSquare sq2, out bool forward)
        {
            if (maze.IsSolved)
            {
                throw new Exception("Maze is already solved.");
            }

            List <WallPosition> openWalls;

            while (true)
            {
                // Get a current square but leave it in the queue.
                int p = SelectPathIdx();
                sq1 = list[p];

                // Possible choices of open walls (not visited).
                openWalls = OpenWalls(sq1, true);

                if (openWalls.Count == 0)
                {
                    list.RemoveAt(p);
                    MarkDeadBranch(sq1);
                }
                else
                {
                    // If this was the last open wall of sq1, it can be removed from the list.
                    if (openWalls.Count == 1)
                    {
                        list.RemoveAt(p);
                    }

                    break;
                }
            }

            // Select one (any) of the neighbor squares.
            WallPosition wp = SelectDirection(sq1, openWalls);

            sq2     = sq1.NeighborSquare(wp);
            forward = true;

            // Add the next square to the list.
            list.Add(sq2);
            sq2.isVisited = true;
        }
        /// <summary>
        /// Returns the value of a given currently open path.
        /// This value should be minimized.
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>
        protected override double PathValue(int i)
        {
            MazeSquare          sq1       = list[i];
            List <WallPosition> openWalls = OpenWalls(sq1, true);

            if (openWalls.Count == 0)
            {
                // Immediately report any dead branch.  Otherwise they would never be detected.
                return(double.MinValue);
            }
            WallPosition wp  = SelectDirection(sq1, openWalls);
            MazeSquare   sq2 = sq1.NeighborSquare(wp);

            double d1           = Maze.Distance(referenceSquare, sq1);
            double d2           = Maze.Distance(referenceSquare, sq2);
            double distanceGain = distanceSign * ((d2 - d1) / d1);

            return(distanceGain);
        }
Beispiel #9
0
        /// <summary>
        /// Travel from one visited square to a neighbor square (through an open wall).
        /// </summary>
        /// <param name="sq1">first (previously visited) square</param>
        /// <param name="sq2">next (neighbor) square</param>
        /// <param name="forward">true if the neighbor square was not visited previously</param>
        protected override void StepI(out MazeSquare sq1, out MazeSquare sq2, out bool forward)
        {
            if (maze.IsSolved)
            {
                throw new Exception("Maze is already solved.");
            }

            // Get the current position.
            sq1 = currentSquare;

            // Set a new (valid) current direction.
            Turn();

            sq2     = sq1.NeighborSquare(currentDirection);
            forward = (sq2.isVisited == false);

            // Remember the new position.
            currentSquare = sq2;
            sq2.isVisited = true;
        }