Powershell(オセロ007_ロジック_1:四隅優先)

■石を置くロジックについて考えてみる。
前回オセロのコードを作成したので、石を置くロジックについて少し考えてみる。
今までのコードは人が手動で入力する場合とランダムに配置する場合で作成した。ランダム同士でゲームをする場合、同じルール上で石を裏返すので、先手、後手の有利不利はあるかもしれないが、ほぼ同じ勝率になると思う。実際、5000ゲーム繰り返した際の勝率は、黒 2467 vs 白 2334 vs 引き分け 199(勝率49%)となった。

これから石を置くロジックをいくつか考えるにあたり、その評価をどうしようか?当然、勝率が高い方がいいロジックだろうけど、それぞれのロジックの特徴を示すような指標があると面白いかも。思いつくもので、勝率(黒白の勝ち数、引き分けの数)に加え、最後まで実施できるか(途中で相手の石が0となるか)、四隅の獲得率、勝敗時の石の数、プログラムの実行速度などについても記録してみよう。

では、ロジックについて考えていく。
オセロをやったことがある人ならわかると思うけど、裏返すことができない四隅に石を置くことができれば、かなり有利になる。そのため、ランダムな石の選択に加え、四隅を優先的に置くロジックを追加したものを試してみる。四隅優先vsランダムといった形でゲームを行う。

ランダムの場合のコードは下の通り($logic_num -eq 0)。
まず、空欄(_)となる部分の位置を取得して、$blankArrayとして一覧とする。その後、get-random -input $blankArray -count ([int]::MaxValue) の関数を使用して、取得した一覧の順番をランダムに並びかえる。そして、一覧の頭から置くことができるかを試し、一番初めに置くことができた位置を採用する。置くことができない場合「pass」を返す。
四隅を優先するコードは、ランダムな一覧の先頭に、四隅の位置を加え、初めに四隅におけるか確認する($logic_num -eq 1)。

[String]placeStone($boardData, $logic_num) {

      $logic_num = $this.logic
      
      $position ="00"
      $blankArray=@()
      $inputArray=@()

      for ($n=1; $n -le 8; $n++) {
         for ($m=1; $m -le 8; $m++) {
            if ($boardData[$n][$m] -eq '_') {
               $blankArray+= [string]$n + [string]$m
            }else{
            }
         }
      }

      if ($blankArray.count -eq 0) {
         $position = "pass"
      } else{         
         if ($blankArray.count -eq 1) {
         $inputArray = $blankArray
         } else {          
            if ($logic_num -eq 0) {
               $inputArray = get-random -input $blankArray -count ([int]::MaxValue)

            }elseif ($logic_num -eq 1){
               $inputArray = get-random -input $blankArray -count ([int]::MaxValue)
               $cornerArray = @()
               if ($boardData[1][1] -eq '_') {
                  $cornerArray += "11"
               }
               if ($boardData[8][1] -eq '_') {
                  $cornerArray += "81"
               }
               if ($boardData[1][8] -eq '_') {
                  $cornerArray += "18"
               }
               if ($boardData[8][8] -eq '_') {
                  $cornerArray += "88"
               }
               $inputArray = $cornerArray + $inputArray
            
            }else{
            }
         }
         
         foreach ($position in $inputArray) {
            $tempBoard = [Utility]::copyBoard($boardData)         
            $tempClass = [Player]::new($this.playercolor, $this.logic)
            $tempClass.reverseStones($position, $tempBoard)
                  
            $canBeReversed = [Utility]::compareBoard($tempBoard, $boardData)
            if($canBeReversed) {
               $position = "pass"
            } else {
               break
            }
         }
      }
   return $position
   }

黒(四隅優先)vs白(ランダム)で5000回ゲームを行った結果は次のようになった。
黒 3876 vs 白 961 vs 引き分け 163 (勝率78%)
(ちなみに、黒と白でロジックを交換すると黒 1150 vs 白 3660 vs 引き分け 190となった。)

勝率を見ると、やはり四隅優先の方が勝率が高い。四隅における状態まではランダムで同じなので、この差は四隅に置くかどうかだろう。

最終的な黒の石の数を見ると、黒40のゲームが最も多くなっている(下のグラフ、250ゲーム以上)。そこから数が少なくなるか多くなるにつれてなだらかになる。相手の石を0にして勝つといったゲームは、黒ではなかったけど、白では3回あった。

肝心の四隅に置いた数については、下のようになった(行が黒、列が白、0から4は四隅をとった数)。黒は四隅優先なので、当然多く取っている(1739)。ゲームが8×8の盤上すべてを埋めれば、四隅は白か黒となるので、対角線上の組み合わせとなる(0vs4, 1vs3, 2vs2, 3vs1, 4vs0)。それ以外は、途中で石を置けなくなって終了したゲーム。

プログラムの実行速度はランダム同士で行ったときと変わらなかった(5000ゲームで10分程度)。

四隅をとるのは有利なのは想像つくので、この結果は予想通りだった。