Powershell(オセロ011_ロジック_5:3手先の勝ち筋)
■石を置くロジックについて考えてみる(その5)。
オセロのロジックの5回目。今回は、次に置く石とその結果だけでなく、さらにその先の状況も考えてみる。オセロでは黒と白が交互に石を置くので、黒が石を置いた後(1手目)、白が置くことができる手が数手あり(2手目)、さらにそれぞれの白の手に対して黒が置くことができる手がそれぞれ数手ある(3手目)。そこで、3手目を置いた際に、黒の数が白より多いという状況を作る可能性が高い1手目を選んでいけば、勝率は高くなると思う。
コードは下の通り($logic_num -eq 5)。
空欄(_)の位置を取得して順番をランダムにした後、一覧の頭から実際に置くことができるか試す。置くことができた場合($canBeReversedがtrue)、相手の手で次に起こりうる盤上の状態のリスト($tempboardList)を取得し、さらにそのリストに対して自分の手で起こりうる盤上のリストを取得する。それらを一つのArrayListに加え(AddRangeでリストに加える)、リストの要素(3手目を置いた際の盤上の状態)を確認する。その結果から、(自分の石の数が相手より多い盤上の数)/(起こりうる盤上の数)($win_route/$boardList.count)の比が最も大きい手を選択する。なお、このロジックは処理に時間がかかるし、ゲームの初めはあまり関係ないだろうから、20回目以降で行った。ゲームは、3手先の勝ち筋vsランダムで行う。
elseif ($logic_num -eq 5){
$max_win_route_rate = 0
$tempposition ="00"
$inputArray = get-random -input $blankArray -count ([int]::MaxValue)
$boardList = [System.Collections.ArrayList]::new()
foreach ($position in $inputArray) {
$win_route = 0
$boardList.clear()
$tempBoard = [Utility]::copyBoard($boardData)
$tempClass = [Player]::new($this.playerColor, $this.logic)
$tempClass.reverseStones($position, $tempBoard)
$canBeReversed = [Utility]::compareBoard($tempBoard, $boardData)
if($canBeReversed) {
} else {
if($this.playerColor -eq "●") {
$tempboardList = [System.Collections.ArrayList]::new()
$tempboardList = [Utility]::reversedBoardList($tempBoard, "〇")
foreach ($nextBlackTurnBoard in $tempboardList) {
$boardList.AddRange([Utility]::reversedBoardList($nextBlackTurnBoard, "●"))
}
} elseif ($this.playerColor -eq "〇") {
$tempboardList = [System.Collections.ArrayList]::new()
$tempboardList = [Utility]::reversedBoardList($tempBoard, "●")
foreach ($nextWhiteTurnBoard in $tempboardList) {
$boardList.AddRange([Utility]::reversedBoardList($nextWhiteTurnBoard, "〇"))
}
}
foreach ($field in $boardList) {
$fieldLeth = ""
foreach($item in $field) {
$fieldLeth = $fieldLeth + ($item -join "")
}
$blackcnt = $fieldLeth.Length - ($fieldLeth -replace "●","").Length
$whitecnt = $fieldLeth.Length - ($fieldLeth -replace "〇","").Length
if($blankArray.count -le 40) {
if($this.playerColor -eq "●") {
if($blackcnt -gt $whitecnt) {
$win_route++
}
} elseif ($this.playerColor -eq "〇") {
if($whitecnt -gt $blackcnt) {
$win_route++
}
}
}
}
if ($boardList.count -eq 0) {
} else {
if (($win_route/$boardList.count) -ge $max_win_route_rate) {
$max_win_route_rate = $win_route/$boardList.count
$tempposition = $position
}
}
}
}
$inputArray[0] = $tempposition
}
黒(3手先の勝ち筋)vs白(ランダム)で5000回ゲームを行った結果は、次のようになった。
黒 3391 vs 白 1480 vs 引き分け 129(勝率68%)
勝率は3手先の勝ち筋の方が高くなった。けど、常に勝てる可能性が高い手を選んでいるので、もう少し勝率が高くなってもよさそう。
最終的な黒の石の数を見ると、黒33-39あたりのゲームが多くなっている(下のグラフ、だいたい250ゲーム以上)。黒33と32の部分で大きく差が出ているので、このあたりはロジックの効果が出ていると思う。途中で終わるゲームは少なかった。
四隅に置いた数については、下のようになった(行が黒、列が白、0から4は四隅をとった数)。四隅優先のロジックでは、四隅すべてをとっているゲームが1700回くらいあったので、それに比べると少ない。最多数のロジックと同じくらい。
3手先の盤上の状況をすべて確認しているので、実行速度は今までのロジック(せいぜい10数分程度)より当然長くかかった(5000ゲームで12時間程度)。
あくまで3手先で勝つ可能性が高いところに石を置いているだけなので、実際には3手先で負けていることもあるだろう。プログラム的にはx手先のxを増やすことは可能だけど、意味あるのかな?
次回は、今までで勝率が高くなったものを組み合わせて高い勝率を目指してみる。