ExcelマクロVBAサンプル集 | オセロを作りながらマクロVBAを学ぼう12 | Excelマクロの実用サンプル、エクセルVBA集と解説



最終更新日:2017-12-06

オセロを作りながらマクロVBAを学ぼう12


ExcelマクロVBAでオセロ(リバーシ)を作っていきながらマクロVBAを学ぶ第12回です。

前回は、相手の応手を判定して、自分の置く場所を決められるようにしました。

オセロソフトとしては、そこそこの強さになりました。

今回は、
PC対PCを何十回と対戦させる機能を実装して、
実際に、どの程度強さに違いがあるのかを検証します。
もちろん、結果の記録も必要になります。

追加・変更する機能

・PCの種類分のリーグマッチ(総当り戦、先後両方を戦う)にする。
・終了メッセージを表示しない。
 PC対PCの場合は、パスのメッセージは既に表示していません。
・1試合が終わってもマクロを終了させない。
・対戦結果を記録する。


PCの種類分のリーグマッチ(総当り戦、先後両方を戦う)にする。
PC1〜PC5で、先後入れ替えての総当り戦にします。

Sub 対戦シミュレーション()
  Dim i1 As Long
  Dim i2 As Long
  Dim i3 As Long
  Dim ary
  Sheet1.Unprotect
  Set TargetSheet = Sheet1
  StopMsg = True
  ary = Array("PC1", "PC2", "PC3", "PC4", "PC5")
  With Worksheets("対戦履歴")
    .Range("A1").CurrentRegion.Offset(1).ClearContents
    For i1 = 0 To 4
      For i2 = 0 To 4
        If ary(i1) <> ary(i2) Then
          Sheet1.cmb1.Text = ary(i1)
          Sheet1.cmb2.Text = ary(i2)
          For i3 = 1 To 100
            DoEvents
            Application.Calculation = xlCalculationManual
            Call 対戦開始
            Call 対戦履歴追加
            DoEvents
            Application.Calculation = xlCalculationAutomatic
          Next
        End If
      Next
    Next
  End With
  Sheet1.Protect
  MsgBox "終了"
End Sub

ary = Array("PC1", "PC2", "PC3", "PC4", "PC5")
Array関数を使って、1行で済ませています。

For i1 = 0 To 4
  For i2 = 0 To 4
    If ary(i1) <> ary(i2) Then
これで総当り、かつ、同じPCは対戦しないようにしています。

For i3 = 1 To 100
この100が同じ組み合わせで戦う試合数になります。



終了メッセージを表示しない。

メッセージ抑止に使う、モジュールレベルのPublic変数を追加。
StopMsgがTrueの場合は、メッセージを出さないようにします。

Option Explicit

Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Public TargetSheet As Worksheet
Public 置く石 As Range
Public 相手石 As Range
Public isPCvsPC As Boolean
Public StopMsg As Boolean

Sub 対戦開始()
  With TargetSheet
    If Not StopMsg Then
      If WorksheetFunction.CountA(.Range("盤面")) > 4 Then
        If MsgBox("対局途中です。" & vbLf & vbLf & _
              "新規対局を開始してもよろしいですか?", _
              vbYesNo, "確認") = vbNo Then
          Exit Sub
        End If
      End If
    End If
    If Sheet1.cmb1.Text Like "PC*" And Sheet1.cmb2.Text Like "PC*" Then
      isPCvsPC = True
    Else
      isPCvsPC = False
    End If
    .Range("先番石").Copy Destination:=.Range("手番石")
    .Range("手番石").Offset(, 1) = "の番です。"
    .Range("盤面").ClearContents
    Call 共通変数設定
    Call 石を置く(.Range("盤面").Cells(4, 5), 置く石)
    Call 石を置く(.Range("盤面").Cells(5, 4), 置く石)
    Call 石を置く(.Range("盤面").Cells(4, 4), 相手石)
    Call 石を置く(.Range("盤面").Cells(5, 5), 相手石)
    Call 置ける場所表示
    If isPC Then
      Call 次手着手(次手候補)
    End If
  End With
End Sub

Sub 終局処理()
  If StopMsg Then Exit Sub
  With TargetSheet
    Select Case True
      Case .Range("先番石").Offset(, 2).Value > .Range("後番石").Offset(, 2).Value
        MsgBox "終局" & vbLf & vbLf & "●先手番「" & Sheet1.cmb1.Text & "」の勝ちです。"
      Case .Range("先番石").Offset(, 2).Value < .Range("後番石").Offset(, 2).Value
        MsgBox "終局" & vbLf & vbLf & "○後手番「" & Sheet1.cmb2.Text & "」の勝ちです。"
      Case Else
        MsgBox "終局" & vbLf & vbLf & "引き分けです。"
    End Select
    .Range("手番石").Clear
    .Range("手番石").Offset(, 1).ClearContents
  End With
End Sub

赤太字の部分が追加された場所です。



1試合が終わってもマクロを終了させない。

今までは、終局の時、
End
これで、マクロそのものを終了させていましたが、
対戦を続けるために、マクロは終了しないようにします。

Function 終局確認() As Boolean
  Dim myRng As Range
  Dim isPass As Boolean
  With TargetSheet
    If WorksheetFunction.CountA(.Range("盤面")) = 64 Then
      Call 終局処理
      終局確認 = True
      Exit Function
    End If
    isPass = True
    For Each myRng In .Range("盤面")
      If is置ける全方向(myRng, True) Then
        isPass = False
      End If
    Next
    If isPass = True Then
      isPass = True
      Set 置く石 = 相手石
      For Each myRng In .Range("盤面")
        If is置ける全方向(myRng, True) Then
          isPass = False
        End If
      Next
      If isPass = True Then
        Call 終局処理
        終局確認 = True
        Exit Function
      End If
    End If
  End With
  Call 共通変数設定
End Function

Sub 次手着手(ByVal Target As Range)
  Dim myRng As Range
  Call 共通変数設定
  If is置ける全方向(Target, False) Then
    Call 手番交代
    Call 置ける場所表示
    If 終局確認 Then Exit Sub
    Call パス確認
    If isPC Then
      If Not isPCvsPC Then
        Sleep 400
      End If
      Call 次手着手(次手候補)
    End If
  End If
End Sub

赤太字の部分が追加された場所です。

終局確認をFunctionにして、終局の時にTrueを返すようにします。
次手着手で、終局確認がTrueなら、Exit Subすることで、マクロを継続させています。



対戦結果を記録する。

対戦結果を出力するシートを用意します。
シート「対戦結果」を作ります。



A列からE列に結果を出力します。



PC6はまだ作成していませんが、
次回には作成する予定なので、シートには前もって入れておきました。

G列からN列には、A列からE列の結果を集計する関数を入れます。
I3セルには、
=COUNTIFS($A:$A,$G3,$B:$B,I$2,$E:$E,"黒")
I4セルには、
=COUNTIFS($A:$A,$G4,$B:$B,I$2,$E:$E,"白")
G4セルは空白に見えますが、「PC1」が入っています。
表示形式のユーザー定義で、「;;;」として、表示を消しています。
表示形式のユーザー定義は、
正の数の書式;負の数の書式;ゼロの書式;文字列の書式
つまり、正:負;ゼロ;文字、全て省略しているので、何も表示されないことになります。
他のPC部分には、コピペで数式を設定できます。

下の集計部分は、簡単に全体が分かるように、
上部の結果を=でとってきているだけです。


Sub 対戦履歴追加()
  Dim j As Long
  With Worksheets("対戦履歴")
    j = .Cells(.Rows.Count, 1).End(xlUp).Row + 1
    .Cells(j, 1) = Sheet1.cmb1.Text
    .Cells(j, 2) = Sheet1.cmb2.Text
    .Cells(j, 3) = Sheet1.Range("先番石").Offset(, 2)
    .Cells(j, 4) = Sheet1.Range("後番石").Offset(, 2)
    If .Cells(j, 3) > .Cells(j, 4) Then
      .Cells(j, 5) = "黒"
    End If
    If .Cells(j, 3) < .Cells(j, 4) Then
      .Cells(j, 5) = "白"
    End If
  End With
End Sub

シート「対戦履歴」にの最終行の次の行に出力しています。
勝敗については、シート「オセロ」にあるので、
シートのオブジェクト名である、Sheet1を使って取得くしています。
オブジェクト名を使う理由としては、
cmb1やcmb2の値を取得するコード記述が簡単になることです。

このように、インテリセンスも効きます。



実際に戦わせた結果

100戦ずつ戦わせた結果です。



左が先手、上が後手
上段が先手勝ち、下段が後手勝ちです。

予定通りではありますが、
PC1から順に強くなっています。
というか、そのように評価値のポイントを調整した結果ではあります。
偶然の要素もあるので、細かい数値の違いはともかくとして、
全体的に先手が優位な状況にあるようです。
これは一般的に、オセロに置いて先手が優位という事ではなく、
今回のソフトのロジック特有のものだと思います。



今回の実装での強さレベルを判定することが出来ました。
強さを判定できるという事は、
いろいろなパターンで作成していく上で、
対戦させることでより強いソフトになっているかどうかを判定できるという事です。

次回は、もう少し、打つ手を工夫するようにして、
さらに強くしていこうと思います。
少なくとも、PC5に完全に勝ち越せるPC6を作ろうと思います。


13へ続きます。

全体の目次


ここまでのサンプルファイルのダウンロード




同じテーマ「ExcelマクロVBAサンプル集」の記事

アメブロの記事本文をVBAでバックアップする1
数独(ナンプレ)を解くVBAに挑戦1
数独(ナンプレ)を解くアルゴリズムの要点とパフォーマンスの検証1
ナンバーリンク(パズル)を解くVBAに挑戦1
ナンバーリンクを解くVBAのパフォーマンス改善1

新着記事 ・・・新着記事一覧を見る

大量VlookupをVBAで高速に処理する方法について|ExcelマクロVBA技術解説(12月12日)
オセロを作りながらマクロVBAを学ぼう|ExcelマクロVBAサンプル集(11月26日)
ScreenUpdating=False時にエラー停止後にシートが固まったら|ExcelマクロVBA技術解説(11月21日)
データクレンジングと名寄せ|ExcelマクロVBA技術解説(10月20日)
SUMIFの間違いによるパフォーマンスの低下について|エクセル関数超技(6月17日)
条件式のいろいろな書き方:TrueとFalseの判定とは|ExcelマクロVBA技術解説(6月15日)
空白セルを正しく判定する方法2|ExcelマクロVBA技術解説(5月6日)
フルパスをディレクトリ、ファイル名、拡張子に分ける|ExcelマクロVBA技術解説(4月15日)
テキストボックスの各種イベント|Excelユーザーフォーム入門(4月9日)
フォルダ(サブフォルダも全て)削除する、Optionでファイルのみ削除|ExcelマクロVBAサンプル集(4月4日)

アクセスランキング ・・・ ランキング一覧を見る

1.最終行の取得(End,Rows.Count)|ExcelマクロVBA入門
2.RangeとCellsの使い分け方|ExcelマクロVBA入門
3.変数とデータ型(Dim)|ExcelマクロVBA入門
4.Range以外の指定方法(Cells,Rows,Columns)|ExcelマクロVBA入門
5.セルのコピー&値の貼り付け(PasteSpecial)|ExcelマクロVBA入門
6.定数と型宣言文字(Const)|ExcelマクロVBA入門
7.マクロって何?VBAって何?|ExcelマクロVBA入門
8.CSVの読み込み方法|ExcelマクロVBAサンプル集
9.徹底解説(VLOOKUP,MATCH,INDEX,OFFSET)|エクセル関数超技
10.ひらがな⇔カタカナの変換|エクセル基本操作



  • >
  • >
  • >
  • オセロを作りながらマクロVBAを学ぼう12

  • このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。


    記述には細心の注意をしたつもりですが、
    間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
    なお、掲載のVBAコードは自己責任で使ってください。万一データ破損等の損害が発生しても責任は負いません。

    ↑ PAGE TOP