Bomberman의 Minimax


11

Bomberman 게임의 클론을 개발 중이며 다른 유형의 AI를 실험하고 있습니다. 먼저 A *로 상태 공간을 검색하는 데 사용했으며 이제 Minimax 알고리즘으로 다른 접근법을 시도하고 싶습니다. 내 문제는 내가 찾은 모든 미니 맥스 기사가 플레이어가 번갈아 가정한다는 것입니다. 그러나 Bomberman에서는 모든 플레이어가 동시에 행동을 취합니다. 나는 하나의 게임 진드기에 대해 가능한 모든 상태를 생성 할 수 있다고 생각하지만 4 명의 플레이어와 5 개의 기본 액션 (4 이동 및 폭탄 장소)으로 게임 트리의 첫 번째 레벨에서 5 ^ 4 상태를 제공합니다. 그 가치는 다음 단계마다 기하 급수적으로 증가 할 것입니다. 뭔가 빠졌습니까? 그것을 구현하는 방법이 있습니까? 아니면 완전히 다른 알고리즘을 사용해야합니까? 어떤 제안에 감사드립니다


1
이 주제가 약간은 아니지만 AI와 관련하여 좋아하는 것은 AI에 목표 나 성격을 사용하는 것입니다. 비축량 증가, 공격적이지 않음, 복수, 돌진 등을 포함 할 수 있습니다. 목표를 달성하기 위해 어떤 방향으로 나아가 야하는지 대략적으로 알 수 있고 폭탄을 떨어 뜨릴 수 있습니다. 사냥하려는 플레이어 또는 파괴하려는 블록과 합리적으로 가깝습니다).
벤자민 위험 존슨

2
그렇습니다. 몇 가지 빠진 것이 있지만 더 나 빠지기 때문에 지적 해 주셔서 감사하지 않습니다. 5 가지 기본 동작이 없습니다. 일부 정사각형에는 5 개의 "움직임"(4 개의 방향이 있고 여전히 유지됨)이 있습니다. 다른 사람은 3 명 (두 방향으로 막혀 있기 때문에); 평균 4입니다. 그러나 당신은 달리는 동안 폭탄 떨어 뜨릴 수 있습니다 . 따라서 평균 분기 요소는 8입니다.
피터 테일러

몬테 카를로 트리 검색을 사용하여 귀하의 질문에 대한 답변을 드리겠습니다.
SDwarfs 2016 년

Minimax는 Bomberman만큼 선택이 많은 상황에서는 유용하지 않습니다. 움직임이 합리적인지 확인하기에 충분히 멀어지기 전에 검색 기능을 소진합니다.
Loren Pechtel

답변:


8

폭격기 사람과 같은 실시간 전략 게임은 AI와 함께 어려움을 겪고 있습니다. 지능적이기를 원하지만 동시에 완벽하지는 않습니다.

AI가 완벽하다면 플레이어는 좌절 할 것입니다. 항상 손실되거나 초당 .3 프레임을 얻기 때문입니다.

지능이 충분하지 않으면 플레이어가 지루해집니다.

내 추천은 AI가 어디로 가는지를 결정하고 다른 하나는 폭탄을 떨어 뜨리는 것이 가장 좋은시기를 결정하는 두 가지 AI 기능을 갖는 것입니다. 이동 예측과 같은 것을 사용하여 현재 위치에 폭탄을 떨어 뜨릴 경우 위험한 지점을 향해 적군이 움직이고 있는지 확인할 수 있습니다.

난이도에 따라 난이도를 높이거나 줄이기 위해 이러한 기능을 수정할 수 있습니다.


2
시간, 좌절 및 권태는 문제가되지 않습니다. Bomberman의 다양한 AI 접근법에 대한 학사 논문을 쓰고 비교하고 있습니다. 그래서 그것이 더 완벽하다면. 나는 지금 그 minimax에 갇혀있다
Billda

1
minimax 알고리즘에서 겪게되는 문제는 처리 시간입니다. 모든 적 행동을 추적하고 그들의 플레이 스타일과 카운터 플레이 스타일을 결정해야합니다. 이미 알고 계신 것 같지만, 게임 속도를 늦추지 않으면 서 실시간 게임에서 상당히 어려운 작업이 될 수 있습니다. 플레이 트리를 만드는 대신 실시간으로 행동을 결정해야 할 것입니다.
UnderscoreZero

4

아시다시피 Bomberman은 턴제 게임으로 시뮬레이션하기에는 너무 복잡합니다. 가능한 모든 자신의 결정과 다른 모든 플레이어의 가능한 모든 결정을 추정하는 것은 효과가 없습니다.

대신에보다 전략적인 접근 방식을 사용해야합니다.

당신은 스스로에게 물어야합니다 : 폭탄 테러범을 치는 동안 인간 플레이어는 어떻게 결정을 내립니까? 일반적으로 플레이어는 4 가지 기본 우선 순위를 따라야합니다.

  1. 폭탄의 폭발 지역을 피하십시오
  2. 다른 사람들이 폭발 지역을 피할 수 없도록 폭탄을 설치하십시오
  3. 파워 업을 수집
  4. 폭탄을 놓아 바위를 날려 버리다

"위험 맵"을 작성하여 첫 번째 우선 순위를 이행 할 수 있습니다. 폭탄을 배치 할 때 폭탄으로 덮힌 모든 타일은 "위험한"것으로 표시되어야합니다. 폭탄이 폭발할수록 (연쇄 반응을 염두에 두십시오!) 위험 수준이 높아집니다. AI가 위험이 높은 현장에 있음을 알게되면 멀리 떨어져 있어야합니다. 어떤 이유로 든 경로를 플롯 할 때 위험 수준이 높은 필드는 피해야합니다 (인위적으로 더 높은 경로 비용을 추가하여 구현할 수 있음).

AI가 어리석은 결정 (다른 플레이어가 가까이있을 때 탈출하기 어려운 영역에 들어가는 것)으로부터 AI를 보호하기 위해 위험 맵 계산을 더욱 강화할 수 있습니다.

이것은 이미 합리적인 방어 AI를 만들어야합니다. 범죄는 어떻습니까?

AI가 현재 합리적으로 안전하다는 사실을 알면 공격적인 기동을 계획해야합니다. 폭탄 자체를 배치하여 다른 플레이어 주변의 위험지도를 어떻게 증가시킬 수 있는지 고려해야합니다. 폭탄을 심을 위치를 선택할 때, 멀리 이동할 필요가없는 가까운 위치를 선호해야합니다. 또한 결과 위험지도가 적절한 탈출 경로를 허용하지 않을 때 폭탄 위치를 무시해야합니다.


이 게임에 대한 나의 제한된 경험은 유능한 적을 죽이기 위해 보통 여러 개의 폭탄을 배치해야한다는 것입니다. 전략에서는이를 고려해야합니다. 나는 대략 당신의 전략으로 AI와 대결했습니다.
Loren Pechtel

4

나는 하나의 게임 진드기에 대해 가능한 모든 상태를 생성 할 수 있다고 생각하지만 4 명의 플레이어와 5 개의 기본 액션 (4 이동 및 폭탄 장소)으로 게임 트리의 첫 번째 레벨에서 5 ^ 4 상태를 제공합니다.

옳은! 각 게임 틱에 대해 5 ^ 4 (또는 4 ^ 방향으로 걸을 수 있고 폭탄을 멈출 수있는 6? 4)까지 모두 검색해야합니다. 그러나 플레이어가 이미 이동하기로 결정한 경우 이동이 실행될 때까지 시간이 걸립니다 (예 : 10 게임 틱). 이 기간 동안 가능성의 수가 줄어 듭니다.

그 가치는 다음 단계마다 기하 급수적으로 증가 할 것입니다. 뭔가 빠졌습니까? 그것을 구현하는 방법이 있습니까? 아니면 완전히 다른 알고리즘을 사용해야합니까?

해시 테이블을 사용하여 동일한 게임 상태 "하위 트리"를 한 번만 계산할 수 있습니다. 플레이어 A가 위 아래로 걷는다고 상상해보십시오. 다른 모든 플레이어는 "기다리면서"같은 게임 상태에있게됩니다. "왼쪽-오른쪽"또는 "오른쪽-왼쪽"과 동일합니다. "왼쪽 위로"및 "왼쪽 위로"를 이동해도 동일한 상태가됩니다. 해시 테이블을 사용하면 이미 평가 된 게임 상태에 대해 계산 된 점수를 "재사용"할 수 있습니다. 이것은 성장 속도를 상당히 줄입니다. 수학적으로 지수 성장 함수의 기초를 줄입니다. 플레이어가 단지 위 / 아래 / 왼쪽 / 오른쪽 / 정지 위치로 이동할 수있는 경우 복잡도를 얼마나 줄이는 지 이해하기 위해 맵에서 도달 가능한 위치 (= 다른 게임 상태)와 비교하여 한 명의 플레이어 만 가능한 움직임을 살펴 보겠습니다. .

깊이 1 : 5 회 이동, 5 개의 다른 상태,이 재귀에 대한 5 개의 추가 상태

깊이 2 : 25 회 이동, 13 개 상태,이 재귀에 대해 8 개의 추가 상태

깊이 3 : 6125 이동, 25 개의 다른 상태,이 재귀에 대한 12 개의 추가 상태

이를 시각화하려면 자신에게 답하십시오. 한 번의 이동, 두 번의 이동, 세 번의 이동으로지도의 어떤 필드에 도달 할 수 있습니까? 답은 : 시작 위치에서 최대 거리 = 1, 2 또는 3 인 모든 필드입니다.

HashTable을 사용할 때는 도달 가능한 각 게임 상태 (예 : 25의 깊이 3)를 한 번만 평가하면됩니다. HashTable이 없으면 깊이 수준 3에서 25 대신 6125 평가를 의미하는 여러 번 평가해야합니다. 최고 : HashTable 항목을 계산 한 후에는 나중에 단계별로 다시 사용할 수 있습니다 ...

더 깊이 검색 할 가치가없는 증분 심화 및 알파-베타 가지 치기 "잘라 내기"하위 트리를 사용할 수도 있습니다. 체스의 경우 이것은 검색된 노드 수를 약 1 %로 줄입니다. 알파-베타 가지 치기에 대한 짧은 소개는 여기 비디오에서 찾을 수 있습니다 : http://www.teachingtree.co/cs/watch?concept_name=Alpha-beta+Pruning

추가 연구를위한 좋은 시작은 http://chessprogramming.wikispaces.com/Search 입니다. 이 페이지는 체스와 관련이 있지만 검색 및 최적화 알고리즘은 매우 동일합니다.

게임에 더 적합한 다른 (그러나 복잡한) 인공 지능 알고리즘은 "임시 차이 학습"입니다.

문안 인사

스테판

추신 : 가능한 게임 상태의 수를 줄이면 (예를 들어, 맵의 매우 작은 크기, 플레이어 당 하나의 폭탄 만, 다른 것은 없음) 모든 게임 상태에 대한 평가를 미리 계산할 수 있습니다.

--편집하다--

오프라인 계산 된 minimax 계산 결과를 사용하여 뉴런 네트워크를 학습 할 수도 있습니다. 또는이를 사용하여 손으로 구현 한 전략을 평가 / 비교할 수 있습니다. 예를 들어, 제안 된 "특성"과 감지 할 수있는 휴리스틱을 구현할 수 있으며, 어떤 상황에서 전략이 좋은지 알 수 있습니다. 따라서 상황을 "분류"해야합니다 (예 : 게임 상태). 이것은 뉴런 네트워크에 의해 처리 될 수도 있습니다 : 뉴런 네트워크를 훈련시켜 현재 상황에서 어떤 핸드 코딩 전략이 가장 잘 실행되고 있는지를 예측하고 실행하십시오. 이것은 실제 게임에 대해 매우 좋은 실시간 결정을 내려야합니다. 오프라인 계산에 걸리는 시간 (게임 이전)은 중요하지 않기 때문에 달리 수행 할 수있는 심도 제한 검색보다 훨씬 낫습니다.

-편집 # 2-

1 초마다 최고의 움직임 만 다시 계산하면 더 높은 수준의 계획을 시도 할 수도 있습니다. 그게 무슨 소리 야? 1 초 동안 얼마나 많은 움직임을 할 수 있는지 알고 있습니다. 따라서 도달 가능한 위치 목록을 만들 수 있습니다 (예 : 1 초에 3 번 이동하면 도달 가능한 위치는 25입니다). 그런 다음 다음과 같이 계획 할 수 있습니다. "위치 x로 이동하여 폭탄을 배치하십시오". 다른 사람들이 제안한 것처럼 라우팅 알고리즘에 사용되는 "위험"맵을 생성 할 수 있습니다 (x로 이동하는 방법-어떤 경로를 선호해야합니까 (대부분의 경우 가능한 변형이 있음)). 이것은 거대한 HashTable과 비교할 때 메모리 소비가 적지 만 최적의 결과를 얻지 못합니다. 그러나 적은 메모리를 사용하므로 캐싱 효과 (L1 / L2 메모리 캐시를 더 잘 사용)로 인해 더 빠를 수 있습니다.

또한 모두 : 한 선수의 움직임 만 포함하는 사전 검색을 수행하여 결과를 잃어버린 변형을 정렬 할 수 있습니다. 따라서 모든 다른 플레이어를 게임에서 꺼내십시오. 각 플레이어가 잃어 버리지 않고 선택할 수있는 조합. 잃어버린 움직임 만 있다면 플레이어가 가장 오래 살아남는 움직임 조합을 찾으십시오. 이런 종류의 트리 구조를 저장 / 처리하려면 다음과 같은 인덱스 포인터가있는 배열을 사용해야합니다.

class Gamestate {
  int value;
  int bestmove;
  int moves[5];
};

#define MAX 1000000
Gamestate[MAX] tree;

int rootindex = 0;
int nextfree = 1;

각 상태는 평가 "값"을 가지며 이동 중에 "트리"내에 배열 인덱스를 저장하여 이동할 때 (0 = 중지, 1 = 위쪽, 2 = 오른쪽, 3 = 아래쪽, 4 = 왼쪽) 다음 게임 상태에 연결됩니다 [0 ]를 이동합니다 [4]. 재귀 적으로 나무를 만들려면 다음과 같이 보일 수 있습니다.

const int dx[5] = { 0,  0, 1, 0, -1 };
const int dy[5] = { 0, -1, 0, 1,  0 };

int search(int x, int y, int current_state, int depth_left) {
  // TODO: simulate bombs here...
  if (died) return RESULT_DEAD;

  if (depth_left == 0) {
    return estimate_result();
  }

  int bestresult = RESULT_DEAD;

  for(int m=0; m<5; ++m) {
    int nx = x + dx[m];
    int ny = y + dy[m];
    if (m == 0 || is_map_free(nx,ny)) {
      int newstateindex = nextfree;
      tree[current_state].move[m] = newstateindex ;
      ++nextfree;

      if (newstateindex >= MAX) { 
        // ERROR-MESSAGE!!!
      }

      do_move(m, &undodata);
      int result = search(nx, ny, newstateindex, depth_left-1);
      undo_move(undodata);

      if (result == RESULT_DEAD) {
        tree[current_state].move[m] = -1; // cut subtree...
      }

      if (result > bestresult) {
        bestresult = result;
        tree[current_state].bestmove = m;
      }
    }
  }

  return bestresult;
}

동적으로 메모리를 할당하는 것이 실제로 느리기 때문에 이런 종류의 트리 구조는 훨씬 빠릅니다! 그러나 검색 트리를 저장하는 것도 상당히 느립니다. 따라서 이것은 더 많은 영감을줍니다.


0

모두가 돌아가는 것을 상상 하는 것이 도움 이 되겠습니까?

기술적으로, 기본 시스템에서는 실제로 수행하지만 사물이 인터리브되고 겹치 므로 동시에 실행되는 것처럼 보입니다 .

또한 모든 애니메이션 프레임 후에 AI를 실행할 필요는 없습니다 . 많은 성공적인 캐주얼 게임은 1 초에 한 번 정도 AI 알고리즘을 실행하여 AI 제어 캐릭터에게 어디로 가야하는지, 무엇을해야하는지에 대한 정보를 제공 한 다음 해당 정보를 사용하여 AI 캐릭터를 제어합니다. 다른 프레임에.


애니메이션 프레임마다 AI를 계산하는 것이 아니라 1 초마다 AI를 계산하고 있습니다. 매 초마다 제 환경은 모든 플레이어의 행동을 수집하여 새로운 업데이트 된 상태로 보냅니다.
Billda
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.