게임 지도에서 최적의 경로 탐색을 위한 개선된 휴리스틱

게임 지도에서 최적의 경로 탐색을 위한 개선된 휴리스틱

2006월 6월 20일 제2회 인공지능 및 대화형 디지털 엔터테인먼트 컨퍼런스 발표

게임 지도에서 최적의 경로 탐색을 위한 개선된 휴리스틱 2006년 6월 20일 Improved Heuristics for Optimal Pathfinding on Game Maps https://ojs.aaai.org/index.php/AIIDE/article/view/18740

Abstract

  • A* 기반으로 경로 탐색을 안내하는 데 사용되는 휴리스틱 함수는 너무 단순하여 크고 복잡한 게임 세계에서 필요한 패스파인딩을 제공하지 못함
  • 크고 복잡한 게임 맵에서 위치 간 거리를 추정하는데에 효과적인 두가지 휴리스틱을 소개
    • 데드 엔드 휴리스틱: 현재 쿼리에 적합하지 않은 검색 맵 영역을 제거
    • 게이트웨이 휴리스틱: 추정치를 개선하기 위해 게이트웨이를 사용

Introduction

게임 맵이 커지고 복잡해짐에 따라 이러한 단순한 휴리스틱으로는 충분한 목표 안내를 제공할 수 없어 멀리 떨어진 두 맵 위치 사이의 최단 경로를 찾을 때 거의 전체 맵을 탐색하는 경우가 빈번하게 발생한다. 이 문제를 극복하기 위해 사용되는 한 가지 기법은 계층적 경로 찾기. 상위 레이어 중 하나에서 대략적인 경로를 찾은 다음 기본 레이어에서 소규모 로컬 검색을 사용하여 경로를 구체화한다. 이러면 A∗가 더 작은 상태 공간을 탐색하기 때문에 처리 속도가 훨씬 빨라지지만, 반환되는 정보가 최적일 필요가 없다는 점이 단점. 추상화 과정에서 맵의 미세한 디테일 중 일부가 손실되기 때문. 맵에 유닛과 기타 동적 장애물의 수가 증가하면 정확도가 떨어짐. 이 논문에서는 상태 공간 탐색을 줄이면서도 장애물들을 볼 수 있게끔 상태 공간 추상화를 사용해 계층적 보기를 생성하는 대신, 이를 사용해 일반 A∗ 검색을 안내하는 개선된 휴리스틱 함수를 제공. 1) 게임맵에서 경로 찾기 검색을 안내하기 위한 허용 가능한 휴리스틱 측정값 개선 2) 게임맵을 더 작은 영역으로 자동 분해하는 알고리즘 방법

Improved Heuristics

이 지도에서 멀리 떨어진 두 위치 사이의 최단 경로를 찾을 때 옥타일 거리에 기반한 순진한 휴리스틱은 지도의 모든 위치를 탐색할 것. 원하는 목적지로 가는 지름길로 연결되는 경로가 존재하는지 미리 알 수 없기 때문이다. 이 논문에서 제시하는 두 가지 휴리스틱의 기본개념: 주어진 두 위치 사이에서 최적의 경로가 될 수 없는 모든 영역(이 경우에는 회의실)을 미리 식별하고 제외함으로써 이 문제를 완화하는 것

  • 데드 엔드 휴리스틱: 막다른 골목으로 이어지는 영역을 피한다
  • 게이트웨이 휴리스틱: 특정 방을 통과하면 최적 경로가 아닌 경로로만 이동할 수 있음을 인식

휴리스틱을 계산하는 과정

  • 1단계: 맵이 전처리되고 추상 뷰가 생성, 오프라인에서 각 맵에 대해 한 번만 수행 (지도를 더 작은 영역으로 자동 분해한 다음 경로 정보를 계산하는 방식)
  • 2단계: 전처리 단계의 추상 뷰를 사용하여 경로 찾기 검색을 위한 개선된 휴리스틱 추정치를 도출

Dead-End Heuristic

막다른 골목으로 이어지는 방, 즉 현재 이 방에서 목표에 이르는 경로가 없는 경우(들어온 입구를 통해 다시 나가는 것 제외)에는 이를 바로 알 수 있다.

Preprocessing Phase

  • 1단계: 게임 맵을 여러 개의 작은 영역으로 분해
  • 2단계: 여러 영역과 영역 간의 상호 연결을 표현하기 위한 상위 수준 그래프를 구성 그래프의 노드는 영역을 나타내고 노드 사이의 에지는 두 해당 영역 사이의 입구

    Runtime Phase

  • 멀티그래프에서 탐색 (멀티그래프: 맵의 여러구역이 노드로 표현된 그래프)
  • 출발지와 목적지 구역 사이에 있는 관련 구역만 찾아내고 나머지는 막다른 길
  • DFS(깊이우선탐색)을 사용해 관련 구역을 찾는다
    • 출발지와 목적지 사이의 모든 가능한 경로를 찾기 위해 DFS 사용
    • 이미 탐색한 길은 기록해둔다
  • 관련 구역만 남기고 나머지는 배제

단점

  • 맵의 구조에 의해 크게 좌우됨
    • 만약 새로운 경로가 열리면 휴리스틱이 불필요한 구역을 배제하는 데 한계가 생김
    • 다양한 경로가 존재하는 맵이면 효과가 적다.
  • 구역을 너무 작게 나누면 멀티그래프가 커지고 탐색하는 데 시간이 오래 걸림
    • 구역별로 필요한 계산을 해둠으로써 해결할 수 있지만, 그만큼 메모리 사용량이 늘어남

Gateway Heuristic

영역의 입구/출구 사이의 거리를 미리 계산한다.

Preprocessing Phase

  • 이 작업은 미리 오프라인(Preprocessing)에서 수행
  • 경로 탐색 속도에 영향을 주지 않고 빠르게 탐색할 수 있지만, 메모리 사용량은 늘어날 수 있음

  • 맵을 여러 구역으로 나눈 후, 각 구역 사이의 경계를 게이트(Gate)라고 정의 게이트는 맵의 구역을 연결하는 입구나 출구 (방에서 복도로 나가는 문이나, 복도 끝에 있는 통로 등)
  • 게이트는 수평이나 수직 방향으로 설정

  • 이 때, 한 게이트에서 출발해 다른 게이트에 도착할 때까지의 거리를 기록
  • 각 게이트에서 다른 게이트까지의 최단 경로를 여러 번의 A* 탐색을 통해 계산
  • 중요한 점은 게이트 간의 경로를 2방향으로 따로 계산한다는 것
    • 게이트 출발과 도착의 각 가능성에 대해 별도의 거리를 알고 싶기 때문
    • 출발지 게이트에서 도착지 게이트로 가는 경로와 그 반대 경로를 각각 계산
    • 하나의 비용 값만 계산할 때보다 런타임 중에 훨씬 더 정확한 휴리스틱 추정치를 얻을 수 있다
  • 각 게이트 간에는 4가지 비용이 저장됨
    • 예를 들어, 방 A에서 방 B로 가는 경로와 방 B에서 방 A로 돌아가는 경로는 다를 수 있으므로, 방향을 고려한 경로 계산이 이루어짐

Runtime Phase

런타임 단계는 아래의 휴리스틱 함수를 사용하는 일반 A* 검색

  • A* 알고리즘은 게이트 간 미리 계산된 거리 정보를 활용하여 경로 탐색을 진행

  • hG(n,g): 출발점 n에서 목표점 g까지의 거리를 추정한 결과값
  • hl(n,Gi​): 현재위치 n에서 가장 가까운게이트 Gi까지의 거리
  • H(Gi​,Gj​): 게이트Gi와 게이트Gj 사이의 미리 계산된 최단 거리
  • hl(Gj​,g): 목표 위치 g에서 가장 가까운 게이트 Gj까지의 거리

이 함수를 통해 모든 게이트 조합을 계산하여, 출발지와 목표지 사이에서 최단 경로를 제공하는 게이트들을 찾는다.

  • 모든 게이트 쌍 Gi와 Gj의 경로를 비교한 후, 가장 짧은 경로를 선택
  • 모든 가능한 게이트 경로 중에서 가장 짧은 경로를 선택

단점

  • 게이트의 크기가 클수록 경로 탐색에서 약간의 오류가 발생할 수 있음
    • 출발지에서 게이트까지의 거리나 도착지에서 게이트까지의 거리 계산이 조금 부정확해질 수 있기 때문
    • 일반적으로 이러한 오차는 크지 않음

Decomposition Algorithm

맵을 여러 개의 작은 구역으로 자동으로 나누는 방법을 설명하는 파트

의사코드

Automatic Map Decomposition

# 맵의 모든 타일을 '통과 가능(free)'으로 초기화
for 모든  타일:
    zone(tile) = 'free'
end for

# 현재 구역 번호를 1로 시작
currZone = 1

# 반복적으로 구역을 생성
repeat:
    # 아직 구역이 할당되지 않은 가장 왼쪽 위의 통과 가능한 타일을 찾음
    (xLeft, y) = 맵에서 가장 위쪽의 왼쪽 타일  'free(통과가능)'한 타일을 찾음
    
    # 오른쪽과 왼쪽 경계가 줄어들었는지 체크할 변수 초기화
    shrunkR = False
    shrunkL = False

    repeat:
        # 현재 라인의 타일을 벽이나 이미 할당된 구역을 만날 때까지 오른쪽으로 채움
        x = xLeft
        zone(x, y) = currZone
        while (x + 1, y) 'free'이고 (x + 1, y - 1) '!free'일 때까지:
            x = x + 1
            zone(x, y) = currZone
        end while

        # 만약 오른쪽 경계가 줄어들었다가 다시 커지면, 구역 채우기를 멈춤
        if (x + 1, y - 1) == currZone:
            shrunkR = True
        # (x, y - 1)가 현재 구역이 아니고 줄어든 오른쪽이라면:
        else if  (x, y - 1) != currZone && (x, y - 1) == shrunkR:
            # 이미 채운 라인을 되돌림
            while (x, y) == currZone:
                Zone(x, y) = 'free'
                x = x - 1
            end while
            break
        end if

        # 다음 줄로 이동, 같은 x 위치에서 시작
        (x, y) = (xLeft, y + 1)
        
        # 장애물이 있으면 구역 내부에서 오른쪽으로 이동
        while (x, y) != 'free' && zone(x, y - 1) == currZone:
            x = x + 1
        end while

        # 왼쪽으로 이동하며 구역 경계 설정
        while (x - 1, y) == 'free' && (x - 1, y - 1) != 'free':
            x = x - 1
        end while

        # 만약 왼쪽 경계가 줄어들었다가 다시 커지면, 구역 채우기를 멈춤
        if (x - 1, y - 1) == currZone:
            shrunkL = True
        else if (x, y - 1) != currZone && (x, y - 1) ==  :
            break  # 채우기 중단
        end if

    until break  # 구역을  채울 때까지 반복

    # 다음 구역 번호로 이동
    currZone = currZone + 1

until 맵에서  이상 통과 가능한 타일이 없을 때까지 반복

초기화

  • 맵의 모든 타일을 “통과 가능” 상태로 설정
  • 첫 번째 구역부터 시작하며, 구역 번호는 1로 설정됨

구역 채우기

  • 맵에서 가장 왼쪽 위에 있는 통과 가능한 타일을 찾음
  • 이 타일을 시작점으로 새로운 구역을 생성
  • 줄 단위로 타일을 오른쪽으로 이동하며, 벽이나 다른 구역을 만날 때까지 구역을 채워나감.

경계가 커지거나 줄어드는지 확인

  • 구역을 채우는 과정에서, 오른쪽과 왼쪽 경계가 커지거나 줄어드는지 확인
  • 만약 구역의 경계가 줄어들었다가 다시 커지면, 구역 채우기를 멈추고 현재 구역을 종료

다음줄로 이동

  • 한 줄을 다 채웠으면 아래 줄로 이동하여 다시 채우기를 시작
  • 이때, 왼쪽 경계부터 오른쪽으로 이동하며 채워나감

구역이 다 채워지면 다음 구역으로 이동

  • 하나의 구역이 다 채워지면, 맵에서 남은 통과 가능한 타일을 찾아서 새로운 구역 시작
  • 맵의 모든 타일이 할당될 때까지 반복

그림 4는 분해 알고리즘이 어떻게 작동하는지 보여주는 예시

  • 왼쪽 위 이미지는 분할되지 않은 맵
  • 오른쪽 위 이미지는 알고리즘이 시작된 상태
    • 4번째줄이 위쪽으로 열려있기 때문에 중지되었음 ((x + 1, y − 1) != free 조건에 걸림)
  • 왼쪽 아래 이미지는 구역 채우기를 완료한 상태
  • 마지막 이미지에선 다음 영역 채우기를 시작한 상태

Empirical Evaluation

평가시작.

테스트맵은 데모맵과 ‘발더스게이트2’에서 가져온 맵으로 실험한다.

  • 각 맵에 대해 1000번의 경로 탐색을 무작위 시작과 목표지점으로 실행
  • 논문에서 기술한 휴리스틱과 기존의 옥타일 휴리스틱을 비교 분석
  • 탐색에 필요한 노드의 수와 총 실행시간을 기록 (노드 수가 적고 실행 시간이 짧을수록 휴리스틱이 더 효율적인 것)

결과를 아래의 표로 정리했다. 옥타일 휴리스틱과 비교한 표.

Octile Heuristic: 일반적으로 그리드 기반 맵에서 사용되는 간단한 휴리스틱

  • Dead-end 휴리스틱과 Gateway 휴리스틱 모두 기존의 옥타일 휴리스틱보다 더 적은 노드를 확장하고 더 짧은 시간에 경로를 찾아냄
  • Gateway 휴리스틱은 모든 맵 유형에서 노드 수의 감소와 실행 시간의 단축 모두 가장 우수한 성능을 보임

Conclusions

  • Dead-End 휴리스틱과 Gateway 휴리스틱 모두 탐색할 때 확장해야 하는 노드 수를 크게 줄였고, 결과적으로 탐색 시간을 단축
  • 향후 연구에서 휴리스틱의 정확성을 더 높이는 방법과, 맵 분할 알고리즘을 다양한 지형 유형에 맞게 최적화하는 방법을 탐구할 필요성이 있음

© 2022. All rights reserved.