150 likes | 523 Views
게임 트리. 게임 트리. 미니맥스 알고리즘 미니맥스 알고리즘의 변형 : 네가멕스 알파 - 베타 가지치기 수순 정렬 방법 알타베타의 개선. 게임 트리. 체스나 장기 등 두 플레이어가 번갈아서 수를 쓰는 게임들은 주로 게임 트리 개념 사용 게임 트리는 각각의 노드가 게임의 한 상태 ( 말들의 위치 ) 를 의미하며 각 노드의 자식 노드들은 한 수 (move) 이후에 도달할 수 있는 다음 위치들을 의미하는 특별한 트리 게임 트리를 이용하여 다음 수순을 미리 예측하고 , 가장 유리한 수를 찾음
E N D
게임 트리 • 미니맥스 알고리즘 • 미니맥스 알고리즘의 변형: 네가멕스 • 알파-베타 가지치기 • 수순 정렬 방법 • 알타베타의 개선
게임 트리 • 체스나 장기 등 두 플레이어가 번갈아서 수를 쓰는 게임들은 주로 게임 트리 개념 사용 • 게임 트리는 각각의 노드가 게임의 한 상태(말들의 위치)를 의미하며 각 노드의 자식 노드들은 한 수(move) 이후에 도달할 수 있는 다음 위치들을 의미하는 특별한 트리 • 게임 트리를 이용하여 다음 수순을 미리 예측하고, 가장 유리한 수를 찾음 • 게임 트리 검색 가정 사항 : 한 플레이어에게 유리한 수는 상태 플레이어에게 불리한 수
시간과 용량이 허용하는 한도 내에서 깊이 검색의 수준이 달라진다.
미니멕스 알고리즘 • 상대에 대한 최소값을 찾음으로써 플레이어 자신에 대한 최대값을 얻음 • 구현 코드 p.334
int maximize(int ply) { if (ply == 0 || game_over()) return evaluate_current_board(); int best = -infinity; for (Move *m = first_available_move(); m != NULL; m = next_available_move()) { make_move(m); int new_value = minimize(ply - 1); unmake_move(m); if (new_value > best) best = new_value; } return best; }
Move *which_move_shall_I_take(int ply) { Move* best_move; int best_value = -infinity; for (Move *m = first_available_move(); m != NULL; m = next_available_move()) { make_move(m); int new_value = maximize(ply); unmake_move(m); if (new_value > best_value) { best_value = new_value; best_move = m; } } return best_move; }
미니맥스 알고리즘의 변형: 네가멕스 • 미니맥스 알고리즘에서 최소값과 최대값을 각각 개별적인 함수로 구현됨 • 실제 최대값과 최소값을 구하는 과정은 동일 : 항상 최고의 수를 찾되 그것이 나의 수이면 최대값, 상대의 수이면 최소값으로 간주하면 됨 • 알고리즘 전체를 재귀적으로 호출되는 함수 하나로 줄임 • 구현 코드 p.335
int negamax(int ply) { if (ply == 0 || game_over()) return evaluate_current_board(); int best = -infinity; for (Move *m = first_available_move(); m != NULL; m = next_available_move()) { make_move(m); int new_value = -negamax(ply - 1); unmake_move(m); if (new_value < best) best = new_value; } return best; }
알파-베타 가지치기 (1) • 어떠한 경우 게임 트리의 특정한 가지는 더 이상 탐색에 나갈 필요가 없다는 점에 기반한 알고리즘 • 상대가 현재 위치 이후의 어떤 지점에서 더 유리한 결과를 얻을 수 있다면, 현재 위치를 만드는 수는 나에게 무조건 불리하므로 더 이상 고려할 필요가 없다는 방식 적용 => 나에게 불리한 수가 만들어지는 지점부터는 트리의 가지를 pruning하게 됨
알파-베타 가지치기 (2) • 게임 트리 검색의 매순간마다 현재까지의 탐색에서 나에게 가장 유리한 수의 최대값과 상대에게 가장 유리한 최대값을 기억해야 함 (현재의 검색에서 상대의 현재 최대값이 나의 현재 최대값보다 크다면 그 부분 이하는 더 이상 고려할 필요가 없다) • 최대한 빨리 필요없는 가지들을 쳐낼 수 있으면 검색 속도가 훨씬 빨라질 것임 : 각 지점에서 최고의 수가 첫번째 자식 노드이어야 함 (검색을 마치지 않고도 자식 노드들을 정렬 시키는 알고리즘 사용)
int alphabeta(int ply, int alpha, int beta) { if (ply == 0 || game_over()) return evaluate_current_board(); for (Move *m = first_available_move(); m != NULL; m = next_available_move()) { make_move(m); int new_value = -alphabeta(ply - 1, -beta, -alpha); unmake_move(m); if (new_value > beta) return new_value; // prune if (new_value < alpha) alpha = new_value; // update our "best so far" } return alpha; }
수순 정렬 방법 • 모든 수준들을 일일이 검색하는 대신, 이전 수준의 결과를 이용해서 차츰 깊은 수준으로 다음의 수들을 정렬해 나가는 방식
알파-베타의 개선 • 알파-베타 알고리즘에서 알파, 베타의 초기치를 각각 음, 양의 무한으로 하는 대신 그 범위의 하한과 상한으로 지정하면 좀 더 빨리 가지치기가 일어남