オセロを作りながらマクロVBAを学ぼう9
ExcelマクロVBAでオセロ(リバーシ)を作っていきながらマクロVBAを学ぶ第9回です。
前回までで人が打つのであれば不自由のない機能が実装できたと思います。
いきなり強いソフトとかは考えずに、
とにかく自動で打つことができる機能を入れてみます。
必要な機能としては、
・手番が「PC」なのかの判定
・「PC」が手番の時に打つべき場所を決める
・「PC」が手番の時に石を打つ
・PCが打つときは、少し待ち時間を作る
・PCvsPCの時は、待ち時間を無くす。
・PCvsPCの時は、パスのメッセージを表示しない。
難しいのは、
打つべき場所を決める
ここになりますが、
今回は、打てる場所から適当に選択することにします。
適当に打つので、当然弱いのはあたりまえです。
とにかく、自動で打ち返してくれるようにします。
さらに、PCvsPCで、全自動対戦もできるようにしておきます。
PC対戦のプロシージャーは今後増えそうなので、
標準モジュールを挿入して、
Module2
新規プロシージャーは、こちらに追記していくことにします。
手番が「PC」なのかの判定
Function isPC() As Boolean isPC = False With TargetSheet If .Range("手番石").Font.Color = .Range("先番石").Font.Color Then If Sheet1.cmb1.Text Like "PC*" Then isPC = True End If Else If Sheet1.cmb2.Text Like "PC*" Then isPC = True End If End If End With End Function |
Like "PC*"
このようにしたのは、
今後、PCの強さによって複数作った時のための布石になります。
「PC」が手番の時に打つべき場所を決める
is置ける全方向
これを使って、石が置ける場所を全て取得します。
Function 次手候補() As Range Dim ix As Long Dim myRng As Range Dim aryRng() As Range With TargetSheet ix = 0 For Each myRng In .Range("盤面") If is置ける全方向(myRng, True) Then ReDim Preserve aryRng(ix) Set aryRng(ix) = myRng ix = ix + 1 End If Next Randomize ix = Int(Rnd * (UBound(aryRng) + 1)) Set 次手候補 = aryRng(ix) End With End Function |
配列を使っています、配列については、
配列の使い方について
動的配列
これらのページを参照してください。
石が置ける場所を、
is置ける全方向
これで取得したら、その場所(セル)を配列に入れます。
全ての置ける場所が取得出来たら、
配列のなかから、ランダムに1セルに決めます。
Rnd
これを使う前に、
Randomize
こちらを実行しておかないと、乱数表が更新されないので、結果として毎回同じになってしまいます。
配列の要素数内での乱数作成になります。
指定範囲内の乱数は、一般的には、
Int((最大値 - 最小値 + 1) * Rnd + 最小値))
となります。
今回の場合は、配列の最小値は0なので、数式が簡単になってます。
・「PC」が手番の時に石を打つ
・PCが打つときは、少し待ち時間を作る
・PCvsPCの時は、待ち時間を無くす。
・PCvsPCの時は、パスのメッセージを表示しない。
赤太字が変更箇所です。
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 Sub 対戦開始() With TargetSheet If WorksheetFunction.CountA(.Range("盤面")) > 4 Then If MsgBox("対局途中です。" & vbLf & vbLf & _ "新規対局を開始してもよろしいですか?", _ vbYesNo, "確認") = vbNo Then Exit Sub 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 |
PCvsPCの判定と、
PCが先番の時に、直ぐに打ち始めるようにしています。
Sub 次手着手(ByVal Target As Range) Call 共通変数設定 If is置ける全方向(Target, False) Then Call 手番交代 Call 置ける場所表示 Call 終局確認 Call パス確認 If isPC Then If Not isPCvsPC Then Sleep 400 End If Call 次手着手(次手候補) End If End If End Sub |
人間にしろPCにしろ、
石を置くときはは、このプロシージャーを経由させていますので、
次の手番がPCの時には、自動で撃たせるようにしています。
Sub パス確認() Dim myRng As Range Dim isPass As Boolean With TargetSheet isPass = True For Each myRng In .Range("盤面") If is置ける全方向(myRng, True) Then isPass = False Exit For End If Next If isPass = True Then If Not isPCvsPC Then If .Range("手番石").Font.Color = .Range("先番石").Font.Color Then MsgBox "●先手番「" & Sheet1.cmb1.Text & "」" & vbLf & vbLf & "パス" Else MsgBox "○後手番「" & Sheet1.cmb2.Text & "」" & vbLf & vbLf & "パス" End If End If Call 手番交代 Call 置ける場所表示 Call 終局確認 End If End With End Sub |
ここは、PCvsPCの時にメッセージを表示しないようにしているだけです。
すでに必要なプロシージャーはほとんどできているので、
大きな変更も無く、割と簡単にPC対戦を実装できました。
ただし、非常に弱い。
ルールだけ聞いた人が、いきなり始めたととしても大抵は勝てるレベルになります。
とにかく打てる場所に適当に置いているのですから仕方ありません。
さすがに、これでは仕方ないので、
次回は、置く場所を少し厳選してもう少し強くします。
10へ続きます。
全体の目次
1.シートの用意と標準モジュールの挿入
2.ブックを開いたときの処理と初期配置
3.自分の石を置ける場所の判定の整理
4.自分の石を置ける場所の判定の実装
5.シート機能を拡張して今後の準備
6.黒石白石を交互に打って相手の石をひっくり返す
7.パス確認、終局確認、石数取得
8.石を置ける場所の表示とアニメーション
9.PC対戦の実装
10.置く場所に重みを付けて少しだけ強く
11.相手の応手を評価してさらに強く
12.PC対PCの対戦で強さを確認
13.パラメーターと重みを調整してさらに強く
14.やはり「待った」が欲しい
15.棋譜で対局を再現
16.これまでを振り返りつつ全体のまとめ
ここまでのサンプルファイルのダウンロード
同じテーマ「マクロVBAサンプル集」の記事
エクセルでファイル一覧を作成
アメブロの記事本文をVBAでバックアップする1
数独(ナンプレ)を解くVBAに挑戦1
数独(ナンプレ)を解くアルゴリズムの要点とパフォーマンスの検証1
ナンバーリンク(パズル)を解くVBAに挑戦1
ナンバーリンクを解くVBAのパフォーマンス改善1
オセロを作りながらマクロVBAを学ぼう
他ブックへのリンクエラーを探し解除
Excelシートの複雑な計算式を解析するVBA
新着記事 ・・・新着記事一覧を見る
Excelシートの複雑な計算式を解析するVBA|VBAサンプル集(2月18日)
VBAクラスの作り方:独自Rangeっぽいものを作ってみた|VBA技術解説(2月16日)
VBAクラスの作り方:列名のプロパティを自動作成する|VBA技術解説(2月14日)
VBAクラスの作り方:列名の入力支援と列移動対応|VBA技術解説(2月11日)
クラスを使って他ブックのイベントを補足する|VBA技術解説(2月6日)
Excelアドインの作成と登録について|VBA技術解説(2月3日)
参照設定、CreateObject、オブジェクト式の一覧|VBA技術解説(1月20日)
VBAでファイルを規定のアプリで開く方法|VBA技術解説(1月20日)
ドキュメントプロパティ(BuiltinDocumentProperties,CustomDocumentProperties)|VBA技術解説(1月19日)
他ブックへのリンクエラーを探し解除|VBAサンプル集(1月15日)
アクセスランキング ・・・ ランキング一覧を見る
1.最終行の取得(End,Rows.Count)|VBA入門
2.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
3.変数とデータ型(Dim)|ExcelマクロVBA入門
4.Range以外の指定方法(Cells,Rows,Columns)|VBA入門
5.RangeとCellsの使い方|ExcelマクロVBA入門
6.マクロって何?VBAって何?|ExcelマクロVBA入門
7.繰り返し処理(For Next)|ExcelマクロVBA入門
8.とにかく書いて見よう(Sub,End Sub)|VBA入門
9.定数と型宣言文字(Const)|ExcelマクロVBA入門
10.ひらがな⇔カタカナの変換|エクセル基本操作
このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
記述には細心の注意をしたつもりですが、
間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
なお、掲載のVBAコードは自己責任で使ってください。万一データ破損等の損害が発生しても責任は負いません。