2011/07/02

NegaScout

Negamax探索はMinmax探索の実装を簡素化したものであり、NegaAlphaBetaも同様にAlphaBeta探索の実装を簡素化したものである。これらは、minノードにおけるスコアの符号が反転する点を除いては同じである。

しかし、紛らわしいことにNegaScout探索はScout探索のnega実装ではない。NegaScout探索はReinefeldによって考案された手法[1]で、名前の通りScout探索を元にしている。しかし、Scout探索がbranch and boundに似た枝刈りをするのに対して、NegaScout探索はαβ探索に基づいている。Scoutの最初のScout探索の用いるtest関数をNegaScout探索では、αβ探索のnull window searchによって実現している。

null window searchとはα+1=βとしたαβ探索である。このとき、探索によって、どのようなleaf nodeの値であろうともαカットあるいはβカットされることになる。ある枝がαカットされたとき、その枝の真のminmax値はそのαカットされたときの値と等しいかより小さい。βカットも同様である。したがって、ある枝に対してnull window searchを行うことで、その枝の真の値がある値αより大きいか、あるいは等しいまたは小さいということが判別できる。つまり、null window searchを用いることでScout関数におけるtest関数と同等のことを行うことができる。

実際のプログラムは次のようになる。
abstract class NegaScoutPlayer[N <: Node[N]](val maxDepth: Int) extends Player[N] {

  override def play(ply: Int, node: N, last: Move): Move = {
    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))
    }
    val moves = node.possibleMoves()
    var bestMove = Move.empty
    var alpha_ = Int.MinValue + 1
    var beta_ = beta
    for (m <- moves) {
      val n = node.play(m).get
      val (_, s) = play(n, -beta_, -(alpha_ max alpha), depth - 1)
      if (-s > alpha_) {
        if (beta_ == beta || depth <= 2) {
          alpha_ = -s
        } else {
          val (_, s2) = play(n, -beta, s, depth - 1)
          alpha_ = -s2
        }
        bestMove = m
      }
      if (alpha_ >= beta) { // beta cut
        return (m, alpha_)
      }
      beta_ = (alpha_ max alpha) + 1
    }
    (bestMove, alpha_)
  }

  def score(node: N): Int
}


NegaScout探索はScout探索と異なりβ値を活用するため、Scout探索よりも高速な探索となると期待できる。
ベンチマークの結果は次の通り。
, , test = end40.pos
           depth
name               2        3        4        5        6        7        8        9       10
  negaalpha       13      117      139      866     1278     7055    11826    56216   102936
  scout           17      122      184     1355     1746    10638    14448    90827   159611
  negascout       13      118      150      869     1426     6877    11739    50161   107685

, , test = end41.pos

           depth
name               2        3        4        5        6        7        8        9       10
  negaalpha       30      289      525     4332     6865    55580    78076   795144   637477
  scout           31      147      523     1685     7813    16346    62773   259737   720301
  negascout       30      277      498     3942     5522    38672    51316   637813   507317

, , test = end42.pos

           depth
name               2        3        4        5        6        7        8        9       10
  negaalpha       30      223      338     3747     4063    47325    48221   538729   579236
  scout           46      208      507     1796     3929    17116    54538   242091   637888
  negascout       30      177      375     2436     3176    25612    42839   248198   549411

, , test = end43.pos

           depth
name               2        3        4        5        6        7        8        9       10
  negaalpha       49       77      673     1388    10677    23115   115886   319520  1253254
  scout           85      180      501     1792     5469    20568    75687   406273  1449598
  negascout       49       64      455     1241     5358    13714    74902   246768  1342957

, , test = end44.pos

           depth
name               2        3        4        5        6        7        8        9       10
  negaalpha       37      208      575     4023     6969    59839    53319   834028   541004
  scout           51      181      831     1754     6878    14971    45735   135692   426776
  negascout       37      163      718     2376     6146    31217    41518   382253   369021

, , test = end45.pos

           depth
name               2        3        4        5        6        7        8        9       10
  negaalpha       34      370      329     5777     2723    61868    26343   817688   226751
  scout           36      262      313     2588     3061    24128    27437   184520   306221
  negascout       34      341      307     5106     2720    48033    26628   663943   243477

, , test = end46.pos

           depth
name               2        3        4        5        6        7        8        9       10
  negaalpha       25      335      594    10135    11688   124574   152214  1237488  1574325
  scout           25      269      600     4603    12058    52798   159862   639592  1366585
  negascout       25      374      485     9812     9666   120794   121581   867828  1146500

, , test = end47.pos

           depth
name               2        3        4        5        6        7        8        9       10
  negaalpha       47       77      788      843    14354     7810   191791    43789  1106182
  scout           71      171      865     4122    15544    51052   170941   227355   710531
  negascout       47       77      742      709    12574     6465   147226    35518   647303

, , test = end48.pos

           depth
name               2        3        4        5        6        7        8        9       10
  negaalpha       29      313      470     6681     9337    89444   145149  1129818  1887604
  scout           38      235      530     3214     9771    56977   123631   620781  1160128
  negascout       29      237      487     4048     8711    47471   101834   447611  1157189

, , test = end49.pos

           depth
name               2        3        4        5        6        7        8        9       10
  negaalpha       34      273      494     2408     6707    20749   125380   310137  1682987
  scout           48      125      569     1718     7189    43022   168662   703102  1383906
  negascout       34      278      539     1791     6544    15755   119662   171897  1286707

, , test = end50.pos

           depth
name               2        3        4        5        6        7        8        9       10
  negaalpha       33      452      626    15963    10816   534240   202532 25385511  3547451
  scout           42      325      711     5129    10956   102361   213611  1484040  3335089
  negascout       33      323      675    12049    10445   311521   165628  8331136  2730443

, , test = end51.pos

           depth
name               2        3        4        5        6        7        8        9       10
  negaalpha       59      183     1160     2032    31843    24937   479486   347731 11632682
  scout           97      391     1425     2848    20183    58913   516050  1038602 12026764
  negascout       59      202     1030     1938    19853    24097   375925   327750  8490980

, , test = end52.pos

           depth
name               2        3        4        5        6        7        8        9       10
  negaalpha       63      204      992     1946     6498    22494    94032   247170  1771168
  scout           78      404      966     2461     5686    30081   106730   390460  1331091
  negascout       63      180      902     1709     5654    19288    81468   195141  1277140

, , test = end53.pos

           depth
name               2        3        4        5        6        7        8        9       10
  negaalpha       43      350     1214    11389    29471   576664   332677 41483269  4314728
  scout           58      239     1355     3738    26987    71788   377530  1003209  3523635
  negascout       43      349     1278    10972    25288   247619   274617 10298036  3186665

, , test = end54.pos

           depth
name               2        3        4        5        6        7        8        9       10
  negaalpha       23      239      586     2323    14222    22906   211911   292473  2569049
  scout           23      125      385     2688     5905    21854   100181   502976  1062680
  negascout       23      216      371     2194     5870    26600    92194   287651   927408

, , test = end55.pos

           depth
name               2        3        4        5        6        7        8        9       10
  negaalpha       49      322      841     5657    20688    82789   223240  1981849  3913589
  scout           70      524     1076     7771    23559   105182   225428  1312618  4845125
  negascout       49      295      857     4616    20627    59091   189197  1009661  3447413

, , test = end56.pos

           depth
name               2        3        4        5        6        7        8        9       10
  negaalpha       56      148     1532     2013    26438    37070   373227   380459  7594219
  scout           92      466     1758     3716    15043    58080   226731  1140123  7096800
  negascout       56      120     1326     1596    14771    21502   222253   230785  6013316

, , test = end57.pos

           depth
name               2        3        4        5        6        7        8        9       10
  negaalpha       38      289      458     5651     4485   107143    44017  1887772   575659
  scout           60      145      528     1040     4698    13081    39672   105975   569878
  negascout       38      237      507     4475     4477    61001    30822   849439   392082

, , test = end58.pos

           depth
name               2        3        4        5        6        7        8        9       10
  negaalpha       55      828      904    15508    15619   238957   206252  3275672  2451690
  scout           84      298     1401     4369    22385    72483   292685   927379  3730359
  negascout       55      547      863    14095    16348   194209   211595  2727903  2286834

, , test = end59.pos

           depth
name               2        3        4        5        6        7        8        9       10
  negaalpha       18      240      210     3747     2592    63628    31206   690918   271286
  scout           20      150      221     1922     3015    24676    33356   283456   228431
  negascout       18      214      209     2844     2643    58239    30403  1008983   216835


[1] Reinefeld. An improvement of the Scout tree-search algorithm. ICCA Journal (1983) vol. 6 (4) pp. 4-14

0 件のコメント:

コメントを投稿