사용자가 반복된 공격 조합을 쓴다는 가정 하에, 지금까지 눌렀던 공격 조합을 토대로 지금 나올 확률이 가장 높은 공격을 예측한다.
본문
위 플래시에서 공격은 4개고 연이은 공격 3개의 조합을 활용한다. 왼쪽 그림에 보이듯 가능한 조합은 4의 3승 즉 64개다. 크기가 64인 저장 공간(보통은 배열)에 각 조합이 나온 개수를 저장하고 매번 지금 나올 확률이 가장 높은 공격을 예측하는 간단한 방법이다.
예를 들어 방금 나온 공격이 A, 방금 전에 나온 공격이 S라면 ASA, ASS, ASD, ASF중 가장 많이 나온 조합을 찾는다. ASF가 가장 많이 나온 조합이라면 지금 나올 공격을 F라고 예측한다.
하지만 사용자가 SAD라는 조합을 200번쯤 반복하다가 SAF라는 조합을 쓰기 시작하면 컴퓨터는 한동안 공격 F를 맞기만 한다. 해결책은 최근 조합 50개만 저장한다던가 해서 너무 오래된 자료는 버리는 것이다.
몇 가지 세부 사항
길이 64인 벡터를 생성한다. 연이은 공격을 2개 저장하면 바이그램, 3개 저장하면 트라이그램, n(>=4)개 이상 저장하면 그냥 n그램이다.
최근의 조합 50개만 저장하기 위해 saves 배열을 생성한다.
var trigram:Vector.<int> = new Vector.<int>(NUM_MOVES*NUM_MOVES*NUM_MOVES)
const NUM_SAVES:int = 50 // 최근 자료 NUM_SAVES개 만큼만 저장
var saves:Array = []
이 코드는 지금 나올 공격을 예측한다. n그램이니 n차원 배열이 머리 편하지만 1차원 배열로 펼쳤더니 인덱스 구하는 게 좀..
var preIndex:int = moreOld*NUM_MOVES*NUM_MOVES + old*NUM_MOVES
var probable:int = 0
for(var i:int=1 ; i<NUM_MOVES ; i++){
if(trigram[preIndex + i] > trigram[preIndex + i-1]){
probable = i
}
}
방금 전에 나온 공격-방금 나온 공격-지금 나온 공격 조합이 나온 개수를 하나 올린다.
trigram[preIndex + recent] ++
이 코드는 저장된 조합 개수가 51개면 제일 오래된 조합을 빼낸다.
saves.push(preIndex + recent)
if(saves.length > NUM_SAVES) trigram[saves.shift()] --
지금 공격을 한 후에는 '방금 나온 공격'은 '방금 전에 나온 공격', '지금 나온 공격'은 '방금 나온 공격'이 된다.
moreOld = old
old = recent
그런데 별로 알아보기 쉽지는 않은 듯하니 그냥 소스 보세여
참고 자료
AI Game Programming Wisdom 1권 11장 5절 『Using N-Gram Statistical Models to Predict Player Behavior』(품절되서 영어 PDF 파일으로 읽었다 -_- 중고 파는 곳 어디 없나?)