게임 인공지능을 떠나 잠시 서치 알고리즘 문제를 예제와 함께 해결해 보겠다.
예전 주차에서 서치 알고리즘을 다루었었는데 사실 이 알고리즘을 길찾기 뿐만 아니라, 조건만 충족된다면 충분히 다른 경우에서도 사용이 될 수 있다는 것을 되새기기 위해 이런 포스팅을 적어본다. 이번 알고리즘 문제는 다양한 variation이 존재하는 알고리즘이며 강 건너기 라고도 예기한다. 이번 예제에서는 식인종과 선교사를 사용하도록 하겠다.
룰은 이러하다:
예시:
이런식으로 좌->우, 좌<-우 를 보트로 옮겨다니며 사람을 옮기면 되는 게임이다. 이 알고리즘 문제를 priority queue와 서치 알고리즘을 활용해서 어떻게 접근 할 수 있을까?
식인종수 그리고 선교사 수는 인풋값으로 주어져 있다. 서치 알고리즘에서 했었던 것 처럼, 방문했던 state를 set값으로 저장하고, priority_queue를 생성하고, 마지막으로 starting state를 정의하는데 이 starting_state는 (보트가 움직인 횟수, 시작 선교사 수, 시작 식인종 수, 'left' (보트의 위치), [이 상태에 오기까지의 움직임]) 을 정보에 넣어준다. 이렇게 세팅이 되어 while priority_queue: 라는 구문으로 들어가게 된다.
while루프를 돌면서 보트의 움직임 수가 가장 작은 수 대로 뽑게 되는데, 만약 뽑았던 state의 값에서 왼쪽 섬에 있는 식인종 수, 왼쪽 선교사 수, 그리고 보트 위치값을 가져온 그 state가 이미 visited 에 들어가 있다면 루프를 넘기고, 없다면 그 고유의 값들은 visted set에 들어가게 된며 루프가 그래도 진행된다. possible moves 라는 리스트가 주어지는데 이는 한 턴에 옮길 수 있는 모든 사람의 경우의 수를 넣어놓은 리스트이다. 이 옮길 수 있는 모든 경우의 수 들을 가지고 루프를 돌며 이 옮기는 행위가 가능한지 (위의 주어진 조건을 violate 하는지 하지 않는지) 를 판단하여 priority queue에 집어 넣게 된다. 이렇게 루프를 돌아가면서 priority_queue를 지우고, 채워 넣고를 반복하다가 왼쪽 사람의 수가 0이 되면 그 즉시 루프를 탈출하여 그 state까지 오기까지의 움직임들을 반환한다. 만약 priority queue를 끝까지 다 서치했음에도 가능한 수 가 없다면 빈 리스트를 반환하면 해당 알고리즘의 작업이 완료된다.
보이는 것 처럼 아래의 값들을 돌렸을때, 최저의 수로 사람들을 옮기는 답안이 나오는 것을 알 수 있다.