Ejemplo n.º 1
0
        //public List<PathTreeNode> children;

        /// <summary>
        /// Constructor for a step that only has set row/column position info, no parent/previous step
        /// </summary>
        /// <param name="r">Row of the tile this step represents</param>
        /// <param name="c">Column of the tile this step represents</param>
        public PathTreeNode(int r, int c)
        {
            row = r;
            col = c;
            parent = null;
            height = 0; //With no parent, height = 0
            //children = new List<PathTreeNode>(4); //Set initial capacity to 4 because most nodes won't have more than 4 edges, save memory space
            isOrangeStep = false;
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Constructor for a step that can be set if it was made inside of an orange loop in the pathfinding algorithm or not
        /// </summary>
        /// <param name="r">Row of the tile this step represents</param>
        /// <param name="c">Column of the tile this step represents</param>
        /// <param name="parentOfNode">The previous step taken in this possible path, the parent of this node in a tree of all possible paths</param>
        /// <param name="orangeStep">true if this step was made while the player is orange-scented/step was made in an orange loop in the path-finding algorithm</param>
        public PathTreeNode(int r, int c, PathTreeNode parentOfNode, bool orangeStep)
        {
            row = r;
            col = c;
            parent = parentOfNode;
            //children = new List<PathTreeNode>(4); //Set initial capacity to 4 because most nodes won't have more than 4 edges, save memory space

            height = 0;
            PathTreeNode child = this;
            while (child.parent != null)
            {
                height++;
                child = child.parent;
            }

            isOrangeStep = orangeStep;
        }
        /// <summary>
        /// Finds a path through the puzzle originating from startNode and ending at endNode, going across from left to right.
        /// Based on A* pathfinding algorithm, it theoretically is supposed to find the shortest possible path, but this is thus far untested/unproven.
        /// 
        /// First uses buildGraph to determine all possible and relevant edges between each tile/node, then uses a mostly standard A* algorithm, until
        /// an orange tile is encountered and the rules change (because of "scents"). Every time an orange tile is encountered, a nested A*-based loop (referred to as the "orange loop")
        /// is ran (but with orange-scented rules) which essentially starts at the orange tile and seeks any tile that will remove the orange scent, or the endNode.
        /// Every tile encountered that exits the orange loop is added to the main open set (the open set of the normal A* loop) with their cost to get there through the orange loop.
        /// 
        /// </summary>
        /// <returns>Returns a list of all possible paths to the endNode, and the shortest one, or the one with the least tree height, is to be considered the answer</returns>
        public List<PathTreeNode> solve()
        {
            resetGraphEdges();
            buildGraph();

            //A*-based pathfinding algorithm
            List<Node> closedSet = new List<Node>();
            SimplePriorityQueue<Node> openSet = new SimplePriorityQueue<Node>();
            List<Node> closedOrangeSet = new List<Node>();
            SimplePriorityQueue<Node> openOrangeSet;
            List<PathTreeNode> Leaves = new List<PathTreeNode>();

            if(startNode.edges.Count == 0)
            {
                return Leaves;
            }

            startNode.g = 0;
            openSet.Enqueue(startNode, 0);
            PathTreeNode root = new PathTreeNode(startNode.row, -1);
            Leaves.Add(root);
            

            while (openSet.Count > 0)
            {
                Node current = openSet.Dequeue();
                PathTreeNode currentStep = null;

                Predicate<PathTreeNode> matchingCurrentPos = aStep => aStep.row == currentStep.row && aStep.col == currentStep.col;

                if (current == endNode)
                {
                    return Leaves;
                }

                if(current.edges.Count == 0)
                {
                    continue;
                }

                foreach (PathTreeNode leaf in Leaves)
                {
                    if(leaf.row == current.row && leaf.col == current.col)
                    {
                        if(currentStep == null || currentStep.height > leaf.height)
                        {
                            currentStep = leaf;
                        }
                    }
                }
                if (currentStep != null)
                {
                    Leaves.RemoveAll(matchingCurrentPos);
                }

                if(current.color == 1)
                {
                    openOrangeSet = new SimplePriorityQueue<Node>();
                    openOrangeSet.Enqueue(current, current.f);
                    currentStep.isOrangeStep = true;
                    Leaves.Add(currentStep);

                    while(openOrangeSet.Count > 0)
                    {
                        Node currentOrange = openOrangeSet.Dequeue();
                        PathTreeNode currentOrangeStep = null;
                        Predicate<PathTreeNode> matchingCurrentOrangePos = aStep => aStep.isOrangeStep && aStep.row == currentOrangeStep.row && aStep.col == currentOrangeStep.col;

                        if (currentOrange.edges.Count == 0)
                        {
                            continue;
                        }

                        foreach (PathTreeNode leaf in Leaves)
                        {
                            if (leaf.isOrangeStep && leaf.row == currentOrange.row && leaf.col == currentOrange.col)
                            {
                                if (currentOrangeStep == null || currentOrangeStep.height > leaf.height)
                                {
                                    currentOrangeStep = leaf;
                                }
                            }
                        }
                        if (currentOrangeStep != null)
                        {
                            Leaves.RemoveAll(matchingCurrentOrangePos);
                        }

                        closedOrangeSet.Add(currentOrange);
                        foreach (Edge toOrangeNeighbor in currentOrange.edges)
                        {
                            if (closedSet.Contains(toOrangeNeighbor.childNode) || closedOrangeSet.Contains(toOrangeNeighbor.childNode))
                            {
                                continue;
                            }
                            if (toOrangeNeighbor.childNode.col == cols)
                            {
                                toOrangeNeighbor.childNode.row = currentOrange.row;
                            }

                            int currentOrangeG = currentOrange.g + Math.Abs((toOrangeNeighbor.childNode.row - currentOrange.row) + (toOrangeNeighbor.childNode.col - currentOrange.col)) + toOrangeNeighbor.childNode.weight;

                            if (openSet.Contains(toOrangeNeighbor.childNode) && toOrangeNeighbor.childNode.g < currentOrangeG)
                            {
                                continue;
                            }

                            PathTreeNode aNextStep;

                            if ((toOrangeNeighbor.isScented && !toOrangeNeighbor.isOrangeScented) || toOrangeNeighbor.childNode == endNode)
                            {
                                toOrangeNeighbor.childNode.f = currentOrangeG + heuristic(toOrangeNeighbor.childNode.col);
                                toOrangeNeighbor.childNode.g = currentOrangeG;
                                openSet.Enqueue(toOrangeNeighbor.childNode, toOrangeNeighbor.childNode.f);
                                aNextStep = new PathTreeNode(toOrangeNeighbor.childNode.row, toOrangeNeighbor.childNode.col, currentOrangeStep);
                                Leaves.Add(aNextStep);
                                continue;
                            }
                            if(toOrangeNeighbor.childNode.color == 4)
                            {
                                continue;
                            }
                            if (!openOrangeSet.Contains(toOrangeNeighbor.childNode))
                            {
                                toOrangeNeighbor.childNode.f = currentOrangeG + heuristic(toOrangeNeighbor.childNode.col);
                                openOrangeSet.Enqueue(toOrangeNeighbor.childNode, toOrangeNeighbor.childNode.f);
                            }
                            else if (currentOrangeG >= toOrangeNeighbor.childNode.g)
                            {
                                continue;
                            }

                            toOrangeNeighbor.childNode.g = currentOrangeG;
                            toOrangeNeighbor.childNode.f = currentOrangeG + heuristic(toOrangeNeighbor.childNode.col);
                            openOrangeSet.UpdatePriority(toOrangeNeighbor.childNode, toOrangeNeighbor.childNode.f);
                            aNextStep = new PathTreeNode(toOrangeNeighbor.childNode.row, toOrangeNeighbor.childNode.col, currentOrangeStep, true);
                            Leaves.Add(aNextStep);
                        }
                    }
                    Predicate<PathTreeNode> isOrangeStepLeaf = aStep => aStep.isOrangeStep;
                    Leaves.RemoveAll(isOrangeStepLeaf);

                    closedSet.Add(current);
                }
                else
                {
                    closedSet.Add(current);
                    foreach (Edge toNeighbor in current.edges)
                    {
                        if (closedSet.Contains(toNeighbor.childNode))
                        {
                            continue;
                        }
                        if(current.col == -1)
                        {
                            current.row = toNeighbor.childNode.row;
                        }
                        else if(toNeighbor.childNode.col == cols)
                        {
                            toNeighbor.childNode.row = current.row;
                        }

                        int currentG = current.g + Math.Abs((toNeighbor.childNode.row - current.row) + (toNeighbor.childNode.col - current.col)) + toNeighbor.childNode.weight;
                        PathTreeNode aNextStep;

                        if (!openSet.Contains(toNeighbor.childNode))
                        {
                            toNeighbor.childNode.f = currentG + heuristic(toNeighbor.childNode.col);
                            openSet.Enqueue(toNeighbor.childNode, toNeighbor.childNode.f);
                        }
                        else if (currentG >= toNeighbor.childNode.g)
                        {
                            continue;
                        }

                        toNeighbor.childNode.g = currentG;
                        toNeighbor.childNode.f = currentG + heuristic(toNeighbor.childNode.col);
                        openSet.UpdatePriority(toNeighbor.childNode, toNeighbor.childNode.f);
                        aNextStep = new PathTreeNode(toNeighbor.childNode.row, toNeighbor.childNode.col, currentStep);
                        Leaves.Add(aNextStep);
                    }
                }
            }

            return Leaves;
        }