各moveごとにスコアを保持し、sufficient moveとなるごとにスコアを増やしていく。
各ノードにおいて、move orderingを考える際に、sufficient moveのスコアを用いることで「有望そうな」手を先に調べるというheuristicである。
また、killer heuristicと異なり、同じdepthのmoveだけではなく、すべてのdepthのmoveを考慮する。
trait HistoryHeuristic[N <: Node[N]] {
val MIN_DEPTH_FOR_HISTORY = 2
val numHistories: Int
var historyMoves: mutable.Map[Move, Int] = _
def initHistory() {
historyMoves = mutable.Map.empty
}
def reorderByHistory(moves: List[Move]): List[Move] = {
val histList = historyMoves.toList.sortBy(- _._2) map (_._1)
var is = histList intersect moves
if (!is.isEmpty)
is ++ (moves diff is)
else
moves
}
def recordHistory(best: Move, depth: Int) {
// depth > 1: Schaeffer, History Heuristic and
// Alpha-Beta Search Enhancements (1989).
if (depth >= MIN_DEPTH_FOR_HISTORY) {
if (historyMoves contains best) {
historyMoves(best) = historyMoves(best) + (1 << (depth - MIN_DEPTH_FOR_HISTORY))
} else {
historyMoves(best) = 1 << (depth - MIN_DEPTH_FOR_HISTORY)
}
}
}
}
abstract class HistoryPlayer[N <: Node[N]](val maxDepth: Int, override val numHistories: Int) extends Player[N] {
override def play(ply: Int, node: N, last: Move): Move = {
initHistory()
val (m, s) = play(node, Int.MinValue + 1, Int.MaxValue, maxDepth)
m
}
def play(node: N, alpha: Int, beta: Int, depth: Int): (Move, Int) = {
if (depth == 0 || node.isTerminal) {
return (Move.empty, score(node))
}
var moves = node.possibleMoves().toList
var bestMove = Move.empty
var alpha_ = alpha
// use history
moves = reorderByHistory(moves)
for (m <- moves) {
val n = node.play(m).get
val (_, s) = play(n, -beta, -alpha_, depth - 1)
if (-s >= beta) { // beta cut
// record the move into history
recordHistory(m, depth)
return (m, beta)
}
if (-s > alpha_) {
bestMove = m
alpha_ = -s
}
}
// record the best move into history
if (alpha_ > alpha)
recordHistory(bestMove, depth)
(bestMove, alpha_)
}
def score(node: N): Int
}
スコアには2(leafまでのdepth)を用い、また、leafのそばのnodeではsufficient moveという扱いにはしていない[1]。実際にreversiでrandom playerを相手にした結果は、killer moveの方がむしろいいという結果に。
reversiだと手が進むと盤面のmarkerの数は増えていくので、ply違いで共通の盤面というのは基本的になく、何手か進んだ後の盤面で共通のいい手というのは盤面の右のほうと左のほうで別々に展開するという状況しかない。
[1] Schaeffer. The history heuristic and alpha-beta search enhancements in practice. Pattern Analysis and Machine Intelligence, IEEE Transactions on (1989) vol. 11 (11) pp. 1203-1212

0 件のコメント:
コメントを投稿