예제 #1
0
        private int PercolateDown(int hole, PQNode <T> data)
        {
            while (2 * hole <= _size)
            {
                var left  = 2 * hole;
                var right = left + 1;

                var target = left;
                if (right > _size || _heap[left].Priority < _heap[right].Priority)
                {
                    target = left;
                }
                else
                {
                    target = right;
                }

                if (_heap[target].Priority >= data.Priority)
                {
                    break;
                }

                _heap[hole] = _heap[target];
                hole        = target;
            }

            return(hole);
        }
예제 #2
0
 public void Insert(PQNode element)
 {
     list.Add(element);
     if (list.Count > 1)
     {
         BubbleUp();
     }
 }
        public void PriorotyQueue_CountIsUnchagedAfterPeek()
        {
            MaxHeapPriorityQueue pq = new MaxHeapPriorityQueue();

            pq.Enqueue(10, 1);

            PQNode peek = pq.Peek();

            Assert.AreEqual(1, pq.Count);
        }
예제 #4
0
        private int PercolateUp(int hole, PQNode <T> data)
        {
            while (hole > 1 && data.Priority < _heap[hole / 2].Priority)
            {
                _heap[hole] = _heap[hole / 2];
                hole       /= 2;
            }

            return(hole);
        }
예제 #5
0
        private void Resize()
        {
            var newHeap = new PQNode <T> [_heap.Length * 2];

            for (var i = 0; i < _heap.Length; i++)
            {
                newHeap[i] = _heap[i];
            }

            _heap = newHeap;
        }
예제 #6
0
        public void Finding(List <Position> points)
        {
            while (astar.IsExistsCandidate())
            {
                // 제일 좋은 후보를 탐색.
                PQNode candidate = astar.GetBestCandidate();

                // 동일한 좌표를 여러 경로로 찾아서, 더 빠른 경로로 인해서 이미 방문 (closed) 된 경우 무시.
                if (astar.isClosed(candidate.Y, candidate.X))
                {
                    continue;
                }

                // 방문.
                astar.Visit(candidate.Y, candidate.X);

                // 목적지 도착.
                if (astar.ReachedDestination(candidate.Y, candidate.X))
                {
                    break;
                }

                // 상하좌우 등 이동할 수 있는 좌표인지 확인 후 위치 예약.
                int directionLength = Enum.GetValues(typeof(DirectionEx)).Length;
                for (int direction = 0; direction < directionLength; ++direction)
                {
                    int nextY = astar.NextY(candidate.Y, direction);
                    int nextX = astar.NextX(candidate.X, direction);

                    if (Passing(nextY, nextX))
                    {
                        continue;
                    }

                    // 비용 계산.
                    int g = astar.CalculationG(candidate.G, direction);
                    int h = astar.CalculationH(nextY, nextX);

                    // 현재 비용이 다른 경로로 도달하는 비용보다 좋지않을 경우.
                    if (!astar.IsFasterThanPrev(nextY, nextX, g + h))
                    {
                        continue;
                    }

                    // 예약 진행.
                    astar.Reservation(nextY, nextX, g, h);
                    astar.SetParent(nextY, nextX, candidate.Y, candidate.X);
                }
            }

            CompletedPath(points);
        }
예제 #7
0
        //Return a node to be deleted from the queue and
        //then delete it. If the queue is empty,
        //the node priority will be zero:
        public PQNode Dequeue()
        {
            PQNode wpqNode = FindMaxNode();

            if (wpqNode.Priority == 0)
            {
                return(wpqNode);
            }

            //Successfully remove Node
            nodeList.Remove(wpqNode);
            return(wpqNode);
        }
        public void PriorotyQueue_DequeueSingleNodePQ()
        {
            MaxHeapPriorityQueue pq = new MaxHeapPriorityQueue();

            for (int i = 0; i < 5; i++)
            {
                pq.Enqueue(i * 10, i);
            }

            PQNode dequeueNode = pq.Dequeue();

            Assert.AreEqual(40, dequeueNode.Priority);
        }
예제 #9
0
        public void Insert(T data, int priority)
        {
            if (_size == _heap.Length - 1)
            {
                Resize();
            }

            _size++;
            var newNode = new PQNode <T>(data, priority);

            int index = PercolateUp(_size, newNode);

            _heap[index] = newNode;
        }
예제 #10
0
 public void Remove()
 {
     if (list.Count > 1)
     {
         PQNode last = list[list.Count - 1];
         list[0] = last;
         list.RemoveAt(list.Count - 1);
         SinkDown();
     }
     else
     {
         list.RemoveAt(0);
     }
 }
예제 #11
0
            public void insert(PQNode node)
            {
                nodes.Add(node);

                int    i = nodes.Count - 1;
                int    p = parent(i);
                PQNode tmp;

                while (i > 0 && p >= 0 && nodes[i].d < nodes[p].d)
                {
                    tmp      = nodes[p];
                    nodes[p] = nodes[i];
                    nodes[i] = tmp;
                    i        = p;
                    p        = parent(i);
                }
            }
예제 #12
0
        private List <PQNode> nodeList = new List <PQNode>(); //Generic List

        //Add a node to the queue.
        //Returns true if the node was successfully
        //added and false if not (duplicate or invalid
        //priority or item):
        public bool Enqueue(PQNode newNode)
        {
            if (object.Equals(newNode.Item, default(T)) || (newNode.Priority <= 0))
            {
                return(false);
            }

            foreach (PQNode wpqNode in nodeList)
            {
                if ((wpqNode.Priority == newNode.Priority) || object.Equals(wpqNode.Item, newNode.Item))
                {
                    return(false);
                }
            }

            //Operation was Successful
            //Add new node to the list
            nodeList.Add(newNode);
            return(true);
        }
예제 #13
0
        public void SinkDown()
        {
            int    index   = 0;
            int    length  = list.Count;
            PQNode element = list[0];

            while (true)
            {
                int    leftChildIndex  = (2 * index) + 1;
                int    rightChildIndex = (2 * index) + 2;
                PQNode leftChild       = new PQNode(string.Empty, 0);
                PQNode rightChild      = new PQNode(string.Empty, 0);
                int    swap            = 0;
                if (leftChildIndex < length)
                {
                    leftChild = list[leftChildIndex];
                    if (leftChild.priority > element.priority)
                    {
                        swap = leftChildIndex;
                    }
                }
                if (rightChildIndex < length)
                {
                    rightChild = list[rightChildIndex];
                    if (swap == 0 && rightChild.priority > element.priority || swap != 0 && rightChild.priority > leftChild.priority)
                    {
                        swap = rightChildIndex;
                    }
                }
                if (swap == 0)
                {
                    break;
                }
                else
                {
                    list[index] = list[swap];
                    list[swap]  = element;
                    index       = swap;
                }
            }
        }
예제 #14
0
        public void BubbleUp()
        {
            int    index   = list.Count - 1;
            PQNode element = list[index];

            while (index > 0)
            {
                int    parentIndex = (index - 1) / 2;
                PQNode parent      = list[parentIndex];
                Console.WriteLine(parentIndex);
                if (element.priority <= parent.priority)
                {
                    break;
                }
                else
                {
                    list[parentIndex] = element;
                    list[index]       = parent;
                    index             = parentIndex;
                }
            }
        }
예제 #15
0
        //Used internally by Dequeue and Peek
        //to find maximum numerical priority node:
        private PQNode FindMaxNode()
        {
            int maxPriority = -1;
            int targetIndex = -1;

            PQNode wpqNode = new PQNode();

            if (nodeList.Count == 0)
            {
                return(wpqNode);
            }

            for (int i = 0; i < nodeList.Count; i++)
            {
                if (nodeList[i].Priority > maxPriority)
                {
                    maxPriority = nodeList[i].Priority;
                    targetIndex = i;
                }
            }
            wpqNode = nodeList[targetIndex];
            return(wpqNode);
        }
예제 #16
0
    // 셀 기반 위치 입력 -> 내부적으로는 _collision 배열기반 위치 -> 셀 기반 위치값을 반환
    public List <Vector3Int> FindPath(Vector3Int startCellPos, Vector3Int destCellPos, bool ignoreDestCollision = false)
    {
        // ignoreDestCollision 최종 목적지를 충돌처리 할지 여부
        // 만약 목적지에 플레이어가 있어서 못간다고 처리하면 안되니깐, 무조건 간다고 처리하게

        List <Pos> path = new List <Pos>();

        // 점수 매기기
        // F = G + H
        // F = 최종 점수 (작을 수록 좋음, 경로에 따라 달라짐)
        // G = 시작점에서 해당 좌표까지 이동하는데 드는 비용 (작을 수록 좋음, 경로에 따라 달라짐)
        // H = 목적지에서 얼마나 가까운지 (작을 수록 좋음, 고정)

        // (y, x) 이미 방문했는지 여부 (방문 = closed 상태)
        bool[,] closed = new bool[SizeY, SizeX];         // CloseList

        // (y, x) 가는 길을 한 번이라도 발견했는지
        // 발견X => MaxValue
        // 발견O => F = G + H
        int[,] open = new int[SizeY, SizeX];         // OpenList
        for (int y = 0; y < SizeY; y++)
        {
            for (int x = 0; x < SizeX; x++)
            {
                open[y, x] = Int32.MaxValue;
            }
        }

        Pos[,] parent = new Pos[SizeY, SizeX];

        // 오픈리스트에 있는 정보들 중에서, 가장 좋은 후보를 빠르게 뽑아오기 위한 도구
        PriorityQueue <PQNode> pq = new PriorityQueue <PQNode>();

        // CellPos -> ArrayPos
        Pos pos  = Cell2Pos(startCellPos);
        Pos dest = Cell2Pos(destCellPos);

        // 시작점 발견 (예약 진행)
        open[pos.Y, pos.X] = 10 * (Math.Abs(dest.Y - pos.Y) + Math.Abs(dest.X - pos.X));
        pq.Push(new PQNode()
        {
            F = 10 * (Math.Abs(dest.Y - pos.Y) + Math.Abs(dest.X - pos.X)), G = 0, Y = pos.Y, X = pos.X
        });
        parent[pos.Y, pos.X] = new Pos(pos.Y, pos.X);

        while (pq.Count > 0)
        {
            // 제일 좋은 후보를 찾는다
            PQNode node = pq.Pop();
            // 동일한 좌표를 여러 경로로 찾아서, 더 빠른 경로로 인해서 이미 방문(closed)된 경우 스킵
            if (closed[node.Y, node.X])
            {
                continue;
            }

            // 방문한다
            closed[node.Y, node.X] = true;
            // 목적지 도착했으면 바로 종료
            if (node.Y == dest.Y && node.X == dest.X)
            {
                break;
            }

            // 상하좌우 등 이동할 수 있는 좌표인지 확인해서 예약(open)한다
            for (int i = 0; i < _deltaY.Length; i++)
            {
                Pos next = new Pos(node.Y + _deltaY[i], node.X + _deltaX[i]);

                // 유효 범위를 벗어났으면 스킵
                // 벽으로 막혀서 갈 수 없으면 스킵
                // 목적지를 충돌처리 시킬거면 스킵
                if (!ignoreDestCollision || next.Y != dest.Y || next.X != dest.X)
                {
                    if (CanGo(Pos2Cell(next)) == false)                     // CellPos
                    {
                        continue;
                    }
                }

                // 이미 방문한 곳이면 스킵
                if (closed[next.Y, next.X])
                {
                    continue;
                }

                // 비용 계산 (휴리스틱)
                // AStar는 최단경로 찾는애가 아님
                int g = 0;                                                                                    // node.G + _cost[i]; // 내가 시작한 위치에서 가는 비용
                int h = 10 * ((dest.Y - next.Y) * (dest.Y - next.Y) + (dest.X - next.X) * (dest.X - next.X)); // 목적지까지 거리의 절대값만 사용(멘하탄 거리)
                // 다른 경로에서 더 빠른 길 이미 찾았으면 스킵
                if (open[next.Y, next.X] < g + h)
                {
                    continue;
                }

                // 예약 진행
                open[dest.Y, dest.X] = g + h;
                pq.Push(new PQNode()
                {
                    F = g + h, G = g, Y = next.Y, X = next.X
                });
                parent[next.Y, next.X] = new Pos(node.Y, node.X);
            }
        }

        return(CalcCellPathFromParent(parent, dest));
    }
예제 #17
0
        private void AStar()
        {
            // U L D R UL DL DR UR
            int[] deltaY = new int[] { -1, 0, 1, 0 };
            int[] deltaX = new int[] { 0, -1, 0, 1 };
            int[] cost   = new int[] { 10, 10, 10, 10 };

            // 점수 매기기
            // F = G + H
            // F = 최종 점수( 적을 수록 좋음, 경로에 따라 달라짐)
            // G = 시작점에서 해당 좌표까지 이동하는데 드는 비용( 작을수록 좋음)
            // H = 목적지에서 얼마나 가까운지 (작을 수록 좋음, 고정)

            // (Y, X) 이미 방문했는지 여부 기록 (방문 = Closed 상태)
            bool[,] closesd = new bool[_board.Size, _board.Size];

            // (Y, X) 가는 길을 한 번이라도 발견했는지
            // 발견 X => MaxValue;
            // 발견 O => F = G + H
            int[,] open = new int[_board.Size, _board.Size];
            for (int y = 0; y < _board.Size; ++y)
            {
                for (int x = 0; x < _board.Size; ++x)
                {
                    open[y, x] = Int32.MaxValue;
                }
            }

            Pos[,] parent = new Pos[_board.Size, _board.Size];

            // 오픈 리스트에 있는 정보들 중에서, 가장 좋은 후보를 빠르게 뽑아오기 위한 도구
            PriorityQueue <PQNode> pq = new PriorityQueue <PQNode>();

            // 시작점 발견 (에약 진행)
            open[PosY, PosX] = 10 * (Math.Abs(_board.DestY - PosY) + Math.Abs(_board.DestX - PosX));
            pq.Push(new PQNode()
            {
                F = 10 * (Math.Abs(_board.DestY - PosY) + Math.Abs(_board.DestX - PosX)), G = 0, Y = PosY, X = PosX
            });
            parent[PosY, PosX] = new Pos(PosY, PosX);

            while (pq.Count > 0)
            {
                // 제일 좋은 후보를 찾는다
                PQNode node = pq.Pop();

                // 동일한 좌표를 여러 경로로 찾아서, 더 빠른 경로로 인해서 이미 방문한 경우 스킵
                if (closesd[node.Y, node.X])
                {
                    continue;
                }

                // 방문한다
                closesd[node.Y, node.X] = true;

                // 목적지 도착했으면 바로 종료
                if (node.Y == _board.DestY && node.X == _board.DestX)
                {
                    break;
                }

                // 상하좌우 등 이동할 수 있는 좌표인지 확인해서 예약(Open)한다
                for (int i = 0; i < deltaY.Length; ++i)
                {
                    int nextY = node.Y + deltaY[i];
                    int nextX = node.X + deltaX[i];

                    // 유효 범위가 넘어가면 스킵
                    if (nextX < 0 || nextX >= _board.Size ||
                        nextY < 0 || nextY >= _board.Size)
                    {
                        continue;
                    }

                    // 벽으로 막혀있으면 스킵
                    if (_board.Tile[nextY, nextX] == Board.TileType.Wall)
                    {
                        continue;
                    }

                    // 이미 방문한 곳이면 스킵
                    if (closesd[nextY, nextX])
                    {
                        continue;
                    }


                    // 비용 계산
                    int g = node.G + cost[i];
                    int h = 10 * (Math.Abs(_board.DestY - nextY) + Math.Abs(_board.DestX - nextX));

                    // 다른 경로에서 더 빠른 길을 이미 찾았으면 스킵
                    if (open[nextY, nextX] < g + h)
                    {
                        continue;
                    }

                    // 예약 진행
                    open[nextY, nextX] = g + h;
                    pq.Push(new PQNode()
                    {
                        F = g + h, G = g, Y = nextY, X = nextX
                    });
                    parent[nextY, nextX] = new Pos(node.Y, node.X);
                }
            }

            CalcPathFromParent(parent);
        }
예제 #18
0
        void Astar()
        {
            // U L D R UL DL DR UR
            int[] deltaY = new int[] { -1, 0, 1, 0 };
            int[] deltaX = new int[] { 0, -1, 0, 1 };
            int[] cost   = new int[] { 10, 10, 10, 10 };

            // 점수 매기기
            // F = G + H
            // F = 최종 점수 (작을 수록 좋음, 경로에 따라 달라짐)
            // G = 시작점에서 해당 좌표까지 이동하는데 드는 비용 (작을 수록 좋음, 경로에 따라 달라짐)
            // H = 목적지에서 얼마나 가까운지 (작을 수록 좋음, 고정)

            // (y,x) 이미 방문했는지 여부 (방문 = closed 상태)
            bool[,] closed = new bool[_board.Size, _board.Size];    // CloseList

            // (y,x) 가는 길을 한번이라도 발견했는지
            // 발견 X => MaxValue
            // 발견 O => F = G + H
            int[,] open = new int[_board.Size, _board.Size];        // OpenList
            for (int y = 0; y < _board.Size; y++)
            {
                for (int x = 0; x < _board.Size; x++)
                {
                    open[y, x] = Int32.MaxValue;
                }
            }

            Pos[,] parent = new Pos[_board.Size, _board.Size];


            // 오픈리스트에 있는 정보들 중에서, 가장 좋은 후보를 빠르게 뽑아오기 위한 도구.
            PrioityQueue <PQNode> pq = new PrioityQueue <PQNode>();

            // 시작점 발견 (예약을 진행해야 한다)
            open[PosY, PosX] = 10 * (Math.Abs(_board.DestY - PosY) + Math.Abs(_board.DestX - PosX));    // Abs는 절대값을 의미한다.
            pq.Push(new PQNode()
            {
                F = 10 * (Math.Abs(_board.DestY - PosY) + Math.Abs(_board.DestX - PosX)), G = 0, Y = PosY, X = PosX
            });
            parent[PosY, PosX] = new Pos(PosY, PosX);

            while (pq.Count > 0)
            {
                // 제일 좋은 후보를 찾는다.
                PQNode node = pq.Pop();

                // 동일한 좌표를 여러 경로로 찾아서, 더 빠른 경로로 인해서 이미 방문(closed)된 경우 스킵
                if (closed[node.Y, node.X])
                {
                    continue;
                }

                // 방문한다
                closed[node.Y, node.X] = true;
                // 목적지에 도착햇으면 바로 종료
                if (node.Y == _board.DestY && node.X == _board.DestX)
                {
                    break;
                }

                // 상하좌우 등 이동할 수 있는 좌표인지 확인해서 예약(open)한다
                for (int i = 0; i < deltaY.Length; i++)
                {
                    int nextY = node.Y + deltaY[i];
                    int nextX = node.X + deltaX[i];

                    // 유효 범위를 벗어났을 경우 스킵한다.
                    if (nextX < 0 || nextX >= _board.Size || nextY < 0 || nextY >= _board.Size)
                    {
                        continue;
                    }

                    // 벽으로 막혀서 갈 수 없으면 스킵한다.
                    if (_board.Tile[nextY, nextX] == Part2_Section2MakeMap.TileType.Wall)
                    {
                        continue;
                    }

                    // 이미 방문한 곳이면 스킵한다.
                    if (closed[nextY, nextX])
                    {
                        continue;
                    }

                    // 비용 계산을 시작한다

                    // G = 시작하면서 이동하면서 필요한 비용
                    int g = node.G + cost[i];

                    // H = 목적지에서 시작점에서 가까운 정도를 나타내는 것
                    int h = 10 * (Math.Abs(_board.DestY - nextY) + Math.Abs(_board.DestX - nextX));

                    // 다른 경로에서 더 빠른 길을 이미 찾았으면 스킵을 해야한다
                    if (open[nextY, nextX] < g + h)
                    {
                        continue;
                    }

                    // 예약을 진행한다
                    open[nextY, nextX] = g + h;
                    pq.Push(new PQNode()
                    {
                        F = g + h, G = g, Y = nextY, X = nextX
                    });
                    parent[PosY, PosX] = new Pos(node.Y, node.X);
                }
            }
            CalcPathFromParent(parent);
        }
예제 #19
0
    public List <Vector3Int> FindPath(Vector3Int startCellPos, Vector3Int destCellPos, bool ignoreDestCollision = false)
    {
        List <Pos> path = new List <Pos>();

        // 점수 매기기
        // F = G + H
        // F = 최종 점수 (작을수록 좋음.)
        // G = 시작점에서 해당 좌표까지 비용
        // H = 목적지에서 얼마나 가까운지


        // 방문 여부
        bool[,] closed = new bool[SizeY, SizeX]; // CloseList

        // (y,x) 가는 길을 한 번이라도 발견했나?
        // 발견x => maxVal
        // 발견o => F = G + H

        int[,] open = new int[SizeY, SizeX];

        for (int y = 0; y < SizeY; y++)
        {
            for (int x = 0; x < SizeX; x++)
            {
                open[y, x] = Int32.MaxValue;
            }
        }

        Pos[,] parent = new Pos[SizeY, SizeX];

        // 오픈 리스트에 있는 정보 중에서, 가장 좋은 후보를 빠르게 뽑기 위한 도구 (Heap 대신)
        PriorityQueue <PQNode> pq = new PriorityQueue <PQNode>();

        Pos pos  = Cell2Pos(startCellPos);
        Pos dest = Cell2Pos(destCellPos);


        // 시작점 발견 (예약 진행)
        open[pos.Y, pos.X] = 10 * (Math.Abs(dest.Y - pos.Y) + Math.Abs(dest.X - pos.X));
        pq.Push(new PQNode()
        {
            F = (Math.Abs(dest.Y - pos.Y) + Math.Abs(dest.X - pos.X)), G = 0, Y = pos.Y, X = pos.X
        });
        parent[pos.Y, pos.X] = new Pos(pos.Y, pos.X);

        while (pq.Count > 0)
        {
            // 제일 좋은 후보를 찾는다.
            PQNode node = pq.Pop();

            // 동일한 좌표를 여러 경로로 찾아서, 더 빠른 경로로 인하여 이미 close에 담긴경우 스킵
            if (closed[node.Y, node.X])
            {
                continue;
            }


            // 방문.
            closed[node.Y, node.X] = true;
            // 목적지다.
            if (node.Y == dest.Y && node.X == dest.X)
            {
                break;
            }

            // 상하좌우 등 이동할 수 있는 좌표인지 확인하고 예약
            for (int i = 0; i < _deltaY.Length; i++)
            {
                Pos next = new Pos(node.Y + _deltaY[i], node.X + _deltaX[i]);

                // 유효 범위를 벗어나면 스킵
                // 벽으로 막혀도.

                if (!ignoreDestCollision || next.Y != dest.Y || next.X != dest.X)
                {
                    if (CanGo(Pos2Cell(next)) == false)
                    {
                        continue;
                    }
                }

                if (closed[next.Y, next.X])
                {
                    continue;
                }

                int g = 0; // node.G + _cost[i];
                int h = 10 * ((dest.Y - next.Y) * (dest.Y - next.Y) + (dest.X - next.X) * (dest.X - next.X));

                // 다른 경로에서 더 빠른 길 찾으면 스킵
                if (open[next.Y, next.X] < g + h)
                {
                    continue;
                }

                // 예약 진행
                open[dest.Y, dest.X] = g + h;
                pq.Push(new PQNode()
                {
                    F = g + h, G = g, Y = next.Y, X = next.X
                });
                parent[next.Y, next.X] = new Pos(node.Y, node.X);
            }
        }

        return(CalcCellPathFromParent(parent, dest));
    }
예제 #20
0
    public List <Tile> PathFind(Tile start, Tile target)
    {
        InitNode();

        PriorityQueue <PQNode> pQueue = new PriorityQueue <PQNode>();

        int startH = CalcDistance(target, start);

        pQueue.Push(new PQNode()
        {
            F = 0 + startH, H = startH, G = 0, X = start.X, Y = start.Y
        });
        _openList[start.X, start.Y] = startH;
        start.PARENT = null;

        Tile tile = start;
        Tile tt;

        while (pQueue.Count > 0)
        {
            PQNode node = pQueue.Pop();

            if (_closedList[node.X, node.Y])
            {
                continue;
            }

            _closedList[node.X, node.Y] = true;

            if (node.X == target.X && node.Y == target.Y)
            {
                break;
            }

            // find next tile이웃 노드를 찾고 fcost를 구해 구해진 코스트가 기존의 예약된(openlist의) 코스트보다 작다면 우선순위 큐에 넣는다.
            for (int i = 0; i < _deltaX.Length; i++)
            {
                int neighborX = node.X + _deltaX[i];
                int neighborY = node.Y + _deltaY[i];

                if (neighborX < 0 || neighborX >= _map._width || neighborY < 0 || neighborY >= _map._height)
                {
                    continue;
                }

                if (CheckType(neighborX, neighborY))
                {
                    continue;
                }

                if (_closedList[neighborX, neighborY])
                {
                    continue;
                }

                TileType type = _map.Tiles[neighborX, neighborY].TILETYPE;

                int delta = 0;

                if (type == TileType.Monster || type == TileType.Hero)
                {
                    delta += 1000;
                }

                int g = node.G + _cost[i] + delta;
                int h = CalcDistance(target, _map._tiles[neighborX, neighborY]);

                if (_openList[neighborX, neighborY] < g + h)
                {
                    continue;
                }

                _openList[neighborX, neighborY] = g + h;
                pQueue.Push(new PQNode()
                {
                    F = g + h, H = h, G = g, X = neighborX, Y = neighborY
                });

                _map._tiles[neighborX, neighborY].PARENT = _map._tiles[node.X, node.Y];
            }
        }

        return(PathTrace(target));
    }
예제 #21
0
        //Returns the next node that would be dequeued
        //without actually removing it.  If the queue
        //is empty, the node priority will be zero:
        public PQNode Peek()
        {
            PQNode wpqNode = FindMaxNode();

            return(wpqNode);
        }
예제 #22
0
        void AStar()
        {
            int[] deltaY = new int[] { -1, 0, 1, 0 };
            int[] deltaX = new int[] { 0, -1, 0, 1 };
            int[] cost   = new int[] { 10, 10, 10, 10 };

            bool[,] closed = new bool[_board.Size, _board.Size]; // CloseList

            int[,] open = new int[_board.Size, _board.Size];     // OpenList
            for (int y = 0; y < _board.Size; y++)
            {
                for (int x = 0; x < _board.Size; x++)
                {
                    open[y, x] = Int32.MaxValue;
                }
            }

            Pos[,] parent = new Pos[_board.Size, _board.Size];

            PriorityQueue <PQNode> pq = new PriorityQueue <PQNode>();

            open[PosY, PosX] = 10 * (Math.Abs(_board.DestY - PosY) + Math.Abs(_board.DestX - PosX));
            pq.Push(new PQNode()
            {
                F = 10 * (Math.Abs(_board.DestY - PosY) + Math.Abs(_board.DestX - PosX)), G = 0, Y = PosY, X = PosX
            });
            parent[PosY, PosX] = new Pos(PosY, PosX);

            while (pq.Count > 0)
            {
                PQNode node = pq.Pop();
                if (closed[node.Y, node.X])
                {
                    continue;
                }

                closed[node.Y, node.X] = true;
                if (node.Y == _board.DestY && node.X == _board.DestX)
                {
                    break;
                }

                for (int i = 0; i < deltaY.Length; i++)
                {
                    int nextY = node.Y + deltaY[i];
                    int nextX = node.X + deltaX[i];

                    if (nextX < 0 || nextX >= _board.Size || nextY < 0 || nextY >= _board.Size)
                    {
                        continue;
                    }
                    if (_board.Tile[nextY, nextX] == Board.TileType.Wall)
                    {
                        continue;
                    }
                    if (closed[nextY, nextX])
                    {
                        continue;
                    }

                    int g = node.G + cost[i];
                    int h = 10 * (Math.Abs(_board.DestY - nextY) + Math.Abs(_board.DestX - nextX));
                    if (open[nextY, nextX] < g + h)
                    {
                        continue;
                    }

                    open[nextY, nextX] = g + h;
                    pq.Push(new PQNode()
                    {
                        F = g + h, G = g, Y = nextY, X = nextX
                    });
                    parent[nextY, nextX] = new Pos(node.Y, node.X);
                }
            }

            CalcPathFromParent(parent);
        }
예제 #23
0
        void AStar()
        {
            // U L D R UL DL DR UR , 대각선 추가
            int[] deltaY = new int[] { -1, 0, 1, 0, -1, 1, 1, -1 };
            int[] deltaX = new int[] { 0, -1, 0, 1, -1, -1, 1, 1 };
            int[] cost   = new int[] { 10, 10, 10, 10, 14, 14, 14, 14 };
            Pos[,] parent = new Pos[_board.Size, _board.Size];

            // 다익스트라와 bfs 모두 사방팔방으로 다 탐색한다.
            // 하지만, A*는 목적지와 가까워지는 방향으로 우선적으로 탐색한다.
            // 점수 매기기
            // F = G + H
            // F = 최종 점수( 작을 수록 좋음, 경로에 따라 달라짐)
            // G = 시작점에서 해당 좌표까지 이동하는데 드는 비용 (작을 수록 좋음, 경로에 따라 달라짐)
            // H = 목적지에서 얼마나 가까운지( 작을 수록 좋음, 고정)

            // (y,x) 이미 방문했는지 여부(방문 = closed 상태)
            bool[,] closed = new bool[_board.Size, _board.Size]; // CloseList

            // (y,x) 가는 길을 한번이라도 발견 했는지
            // 발견X => MaxValue
            // 발견O => F = G + H
            int[,] open = new int[_board.Size, _board.Size]; // OpenList
            for (int y = 0; y < _board.Size; y++)
            {
                for (int x = 0; x < _board.Size; x++)
                {
                    open[y, x] = Int32.MaxValue;
                }
            }

            // 오픈리스트에 있는 정보들 중에서 가장 좋은 후보를 빠르게 뽑아오기 위한 도구
            PriorityQueue <PQNode> pq = new PriorityQueue <PQNode>();

            // 시작점 발견 (예약 진행)
            open[PosY, PosX] = 0 + 10 * (Math.Abs(_board.DestY - PosY) + Math.Abs(_board.DestX - PosX));
            pq.Push(new PQNode()
            {
                F = 10 * (Math.Abs(_board.DestY - PosY) + Math.Abs(_board.DestX - PosX)), G = 0, Y = PosY, X = PosX
            });
            parent[PosY, PosX] = new Pos(PosY, PosX);
            while (pq.Count > 0)
            {
                // 제일 좋은 후보를 찾는다.
                PQNode node = pq.Pop();

                // 동일한 좌표를 여러 경로로 찾아서, 더 빠른 경로로 인해서 이미 방문(closed)된 경우 스킵
                if (closed[node.Y, node.X])
                {
                    continue;
                }

                // 방문한다.
                closed[node.Y, node.X] = true;

                if (node.Y == _board.DestY && node.X == _board.DestX)
                {
                    break;
                }

                // 상하좌우 등 이동할 수 있는 좌표인지 확인해서 예약(open)한다.
                for (int i = 0; i < deltaY.Length; i++)
                {
                    int nextY = node.Y + deltaY[i];
                    int nextX = node.X + deltaX[i];

                    // 유효 범위를 벗어났으면 스킵
                    if (nextX < 0 || nextX >= _board.Size || nextY < 0 || nextY >= _board.Size)
                    {
                        continue;
                    }
                    // 벽으로 막혀서 갈수 없으면 스킵
                    if (_board.Tile[nextY, nextX] == Board.TileType.Wall)
                    {
                        continue;
                    }
                    // 이미 방문한 곳이면 스킵
                    if (closed[nextY, nextX])
                    {
                        continue;
                    }


                    // 비용 계산
                    int g = node.G + cost[i];
                    int h = 10 * (Math.Abs(_board.DestY - nextY) + Math.Abs(_board.DestX - nextX));

                    // 다른 경로에서 더 빠른 길을 이미 찾았으면 스킵
                    if (open[nextY, nextX] < g + h)
                    {
                        continue;
                    }
                    open[nextY, nextX] = g + h;
                    pq.Push(new PQNode()
                    {
                        F = g + h, G = g, Y = nextY, X = nextX
                    });
                    parent[nextY, nextX] = new Pos(node.Y, node.X);
                }
            }

            CalcPathFromParent(parent);
        }