‡๐Ÿ‘ฉ‍๐Ÿ’ป ‡/º Java

[์•Œ๊ณ ๋ฆฌ์ฆ˜] ์ตœ๋‹จ ๊ฑฐ๋ฆฌ | A-Star ์•Œ๊ณ ๋ฆฌ์ฆ˜ (A* algorithm) ๊ตฌ

Trudy | ์†ก์—ฐ 2023. 12. 8. 21:01

๐Ÿ“A* ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋ž€?

 

 

A* ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์ตœ๋‹จ ๊ฑฐ๋ฆฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ค‘ ํ•˜๋‚˜๋กœ, ์ถœ๋ฐœ ๋…ธ๋“œ์—์„œ๋ถ€ํ„ฐ ๋ชฉํ‘œ ๋…ธ๋“œ๊นŒ์ง€ ๊ฐ€๋Š” ์ตœ๋‹จ ๊ฒฝ๋กœ๋ฅผ ์ฐพ์•„๋‚ธ๋‹ค. 

 

์ตœ๋‹จ ๊ฒฝ๋กœ ์•Œ๊ณ ๋ฆฌ์ฆ˜ Visualization

https://qiao.github.io/PathFinding.js/visual/

 


๐Ÿ“์ฝ”๋“œ 

Node.js

package astar;

public class Node {
    Integer x;
    Integer y;
    Integer startd;
    Integer destd;
    Integer total;

    Node parents;

    public Node(Integer x, Integer y) {
        this.x = x;
        this.y = y;
        parents = null;
    }


}

 

Astar.java

package astar;

import java.util.*;

public class Astar {
    final Integer DEFAULT_COST = 10;
    final Integer DEFAULT_DIAGONAL = 14;

    //์ƒํ•˜์ขŒ์šฐ, ๋Œ€๊ฐ์„  ์ƒ์ขŒ ์ƒ์šฐ ํ•˜์ขŒ ํ•˜์šฐ
    final Integer XPOS[] = {0, 0, -1, 1, -1, 1, -1, 1 };
    final Integer YPOS[] = {-1, 1, 0, 0, -1, -1, 1, 1 };

    //๋งต์˜ ํฌ๊ธฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๋ณ€์ˆ˜
    Integer mapX;
    Integer mapY;

    //์—ด๋ฆฐ, ๋‹ซํžŒ ๋ชฉ๋ก ์ €์žฅํ•  ๋ณ€์ˆ˜
    List<Node> open;
    List<Node> close;
    List<Node> block;

    //์ดˆ๊ธฐํ™” ํ•  ๋•Œ ๋งต ์ •๋ณด๋ฅผ ์ „๋‹ฌ ๋ฐ›์•„์„œ ์ถœ๋ฐœ์ง€์™€ ๋ชฉ์ ์ง€์˜ ์ขŒํ‘œ๋ฅผ ๋ณ€์ˆ˜์— ์ €์žฅ
    Integer[][] map;
    Node start;
    Node goal;

    public Astar(Integer[][] map) {
        this.map = map;
        mapX = map[0].length;
        mapY = map.length;

        //์—ด๋ฆฐ ๋ชฉ๋ก, ๋‹ซํžŒ ๋ชฉ๋ก ์ดˆ๊ธฐํ™”
        open = new ArrayList<>();
        close = new ArrayList<>();
        block = new ArrayList<>();

        //์ถœ๋ฐœ์ , ๋„์ฐฉ์ , ์žฅ์• ๋ฌผ ์ดˆ๊ธฐํ™”
        init();
        start.startd = 0;
        start.destd = Math.abs(goal.x - start.x) *10 + Math.abs(goal.y - start.y) *10;
        start.total = start.startd + start.destd;
    }

    void init(){
        for (int i = 0; i < map.length; i++) {
            for (int j = 0; j < map[i].length; j++) {
                if(map[i][j] == 1){
                    System.out.printf("์ถœ๋ฐœ์ : (%d, %d)", j, i);
                    start = new Node(j, i);
                }

                else if(map[i][j] == 2){
                    System.out.printf("๋„์ฐฉ์ : (%d, %d)", j, i);
                    goal = new Node(j, i);
                }
                else if(map[i][j] == 3){
//                    System.out.printf("์žฅ์• ๋ฌผ: (%d, %d)", j, i);
                    block.add(new Node(j, i));
                }
            }
        }
    }

    public void findPath() {
        // ์‹œ์ž‘์ ๋ฅผ '์—ด๋ฆฐ ๋ชฉ๋ก'์— ๋„ฃ๋Š”๋‹ค.
        open.add(start);

        // ์—ด๋ฆฐ ๋ชฉ๋ก์ด ๋น„์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด ๋ฐ˜๋ณต, ๋ฆฌ์ŠคํŠธ๊ฐ€ ๋น„์–ด์žˆ๋Š”์ง€ ์•„๋‹Œ์ง€ ํ™•์ธ์€ ๋ฆฌ์ŠคํŠธ๋ณ€์ˆ˜.isEmpty()
        while(!open.isEmpty()) {
            //์—ด๋ฆฐ ๋ชฉ๋ก์—์„œ F๊ฐ’์ด ๊ฐ€์žฅ ์ ์€ ํ•˜๋‚˜๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค(๊ฐ€์ ธ์˜จ ๋…ธ๋“œ๋Š” ๋ชฉ๋ก์—์„œ ์‚ญ์ œ)
            open.sort(new Comparator<Node>() {
                @Override
                public int compare(Node o1, Node o2) {
                    return o1.total<o2.total ? o1.total:o2.total;
                }
            });

            Node node = open.get(0);
            System.out.printf("\n์—ด๋ฆฐ ๋ชฉ๋ก์—์„œ [%d, %d], Total = %d ๋ฅผ ๊บผ๋‚ด์™”์Šต๋‹ˆ๋‹ค.\n",
                    node.x, node.y, node.total);
            open.remove(0);
            //๊ฐ€์ ธ์˜จ ๋…ธ๋“œ๋Š” ๋‹ซํžŒ ๋ชฉ๋ก์— ๋„ฃ์–ด์ค€๋‹ค.
            close.add(node);

            //๋งŒ์•ฝ ๊ฐ€์ ธ์˜จ ๋…ธ๋“œ๊ฐ€ ์ตœ์ข… ๋ชฉ์ ์ง€๋ฉด, ์ตœ์ข… ๊ฒฝ๋กœ ์ถœ๋ ฅ!
            if(goal.x==node.x && goal.y==node.y) {
                printPath(node);
                break;
            }

            else {
                // ๊ฐ€์ ธ์˜จ ๋…ธ๋“œ์˜ ์ธ์ ‘ ๋…ธ๋“œ ์ค‘ ๊ฐˆ ์ˆ˜ ์žˆ๋Š” ๋…ธ๋“œ์˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ
                // ์ƒ์„ฑํ•œ ๋…ธ๋“œ์˜ ๋ถ€๋ชจ ๋…ธ๋“œ๋ฅผ ํ˜„์žฌ ๋…ธ๋“œ๋กœ ์ง€์ •
                // ์ƒ์„ ํ•œ ๋…ธ๋“œ์˜ FGH ๊ณ„์‚ฐ
                // ์ƒ์„ฑํ•œ ๋…ธ๋“œ๋ฅผ ์—ด๋ฆฐ ๋ชฉ๋ก์— ๋„ฃ๋Š”๋‹ค(์ค‘๋ณต๋œ ๋…ธ๋“œ๋Š” ์ถ”๊ฐ€ X).
                for (int i = 0; i < 8; i++) {
                    int nx = node.x + XPOS[i];
                    int ny = node.y + YPOS[i];

                    if(nx < 0 || ny <0 || nx > mapX || ny > mapY) continue;
                    if(ifContains(block, nx, ny)) continue;
                    if(ifContains(open, nx, ny) || ifContains(close, nx, ny)) continue;

                    Node newNode = new Node(nx, ny);
                    newNode.parents = node;
                    if(i <= 4) {
                        newNode.startd = node.startd + DEFAULT_COST;
                    }
                    else {
                        newNode.startd = node.startd + DEFAULT_DIAGONAL;
                    }
                    newNode.destd = Math.abs(goal.x - nx)*10 + Math.abs(goal.y - ny)*10;
                    newNode.total = newNode.startd + newNode.destd;

                    addAdjacentNodes(newNode);

                }
            }
        }
    }

    private void printPath(Node node){
        // ํŠน์ • ๋…ธ๋“œ๋ฅผ ํ•˜๋‚˜ ์ „๋‹ฌ ๋ฐ›์•„์„œ
        // ๋ถ€๋ชจ ๋ถ€๋ชจ ๋ถ€๋ชจ ์ฐพ์•„๊ฐ€์„œ ์ถœ๋ฐœ์ง€๊ฐ€ ๋‚˜์˜ค๋ฉด
        // ์ถœ๋ฐœ์ง€ ๋ถ€ํ„ฐ ์ถœ๋ ฅ
        if(node.x == start.x && node.y==start.y){
            for (int i = 0; i < mapX; i++) {
                for (int j = 0; j < mapY; j++) {
                    System.out.print(map[i][j]+ " ");
                }
                System.out.println();
            }
            return;
        }
//        System.out.printf("%d, %d \n", node.x, node.y);
        if(node.x == goal.x && node.y == goal.y);
        else map[node.y][node.x] = 8;
        printPath(node.parents);
    }

    private void addAdjacentNodes(Node node) {
        // ์ธ์ ‘๋…ธ๋“œ๋ฅผ ์—ด๋ฆฐ ๋ชฉ๋ก์— ์ถ”๊ฐ€ํ•˜๋Š”๋ฐ ์ค‘๋ณต ์•ˆ๋˜๊ฒŒ
        open.add(node);
//        System.out.printf("์ธ์ ‘ ๋…ธ๋“œ[%d, %d], Total = %d ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n", node.x, node.y, node.total );
    }

    private boolean ifContains(List<Node> list, Integer x, Integer y){
        for (int i = 0; i < list.size() ; i++) {
            if(list.get(i).x == x && list.get(i).y == y ) return true;
        }
        return false;
    }
}

 

Test.java

package astar;

public class Test {
    public static void main(String[] args) {
    
    //์ถœ๋ฐœ์ : 1
    //๋„์ฐฉ์ : 2
    //์žฅ์• ๋ฌผ: 3
        Integer[][] map = {
                {0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,3,0,0,0,0},
                {0,0,0,0,0,3,0,0,0,0},
                {0,0,0,0,0,3,0,2,0,0},
                {0,0,0,0,1,3,0,0,0,0},
                {0,0,0,3,3,3,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0}
        };

        Astar astar = new Astar(map);
        astar.findPath();

    }
}

์‹คํ–‰ ๊ฒฐ๊ณผ

 


๐Ÿ“์ฐธ๊ณ 

https://recall.tistory.com/40