Excel将棋:将棋盤クラスの作成&単体テスト(№7)

Excelで将棋を作ってみましょう。
人vs人で動かしてゲームとして成立するところまでが当面の目標です。
駒クラスを2次元配列(1 To 9, 1 To 9)に入れて将棋盤全体を管理します。
作成するクラス全体の設計は、№2. Excel将棋:クラスの設計、こちらを参照してください。
※クラス名、プロシージャー名、変数名に日本語を使用しています。
将棋盤クラス
将棋盤クラスの設計
種別 | 名称 | 説明 |
プロパティ | 現在盤面 | 駒オブジェクトが入っている2次元配列から表示名の2次元配列を作成する |
プロパティ | 盤面履歴 | 現在盤面をCollection |
プロパティ | 手数 | 現在手数を戻す |
プロパティ | 棋譜 | 1手ずつCollectionに追加 棋譜は、Ki2形式とします。 ▲5ニ銀右上成 ・先手▲後手△ ・到達地点の筋 ・到達地点の段 ・駒の種類 ・駒の相対位置(複数ある場合) ・駒の動作(複数ある場合) ・成・不成・打 |
プロパティ | 棋譜履歴 | 最終手をCollection |
プロパティ | 先手 | 先手True、後手False |
メソッド | 着手 | 引数(元位置, 先位置, 駒名, Optional 手番) 元位置:-1,-1は初期配置 元位置:0,0は駒台から 手番省略時は、プロパティ手番に従う 以下を更新する。 最終手、2次元配列、盤面履歴、棋譜履歴 |
メソッド | 終局判定 | これはかなり難しい・・・ 持駒を含めた全ての駒を使って受けがないかの判定が必要 |
2次元配列(1 To 9, 1 To 9)の各要素に駒オブジェクト(駒クラスのインスタンス)を入れて管理します。
将棋盤クラスのVBA
Option Explicit
Private pAry駒(1 To 9, 1 To 9) As cls駒
Private p先手 As Boolean
Private pCol盤面 As Collection
Private pCol棋譜 As Collection
Private Sub Class_Initialize()
Me.先手 = True
Set pCol盤面 = New Collection
Set pCol棋譜 = New Collection
End Sub
Private Sub Class_Terminate()
Set pCol盤面 = Nothing
Set pCol棋譜 = Nothing
End Sub
'**********************************************************************
' 公開プロパティ
'**********************************************************************
Public Property Get 現在盤面() As String()
Dim ary盤 As Variant
If pCol盤面.Count = 0 Then
ary盤 = pAry駒
Else
ary盤 = pCol盤面(pCol盤面.Count)
End If
Dim out盤面() As String
ReDim out盤面(LBound(ary盤, 1) To UBound(ary盤, 1), _
LBound(ary盤, 2) To UBound(ary盤, 2))
Dim i As Long, j As Long
For i = LBound(ary盤, 1) To UBound(ary盤, 1)
For j = LBound(ary盤, 2) To UBound(ary盤, 2)
If ary盤(i, j) Is Nothing Then
out盤面(i, j) = " "
Else
out盤面(i, j) = ary盤(i, j).表示名称 & _
IIf(ary盤(i, j).先手, "↑", "↓")
End If
Next
Next
現在盤面 = out盤面
End Property
Public Property Get 盤面履歴() As Collection
Set 盤面履歴 = pCol盤面
End Property
Public Property Get 棋譜() As String
棋譜 = pCol棋譜(pCol棋譜.Count)
End Property
Public Property Get 棋譜履歴()
Set 棋譜履歴 = pCol棋譜
End Property
Public Property Get 手数() As String
手数 = pCol棋譜.Count
End Property
Public Property Let 先手(ByVal Value As Boolean)
p先手 = Value
End Property
Public Property Get 先手() As Boolean
先手 = p先手
End Property
'**********************************************************************
' 公開メソッド
'**********************************************************************
'駒が移動できる位置をg位置(行、列)のCollectionで返す
Public Function 駒移動可能位置(ByVal arg位置 As g位置) As Collection
If pAry駒(arg位置.行, arg位置.列) Is Nothing Then Exit Function
Set 駒移動可能位置 = pAry駒(arg位置.行, arg位置.列).駒移動可能位置(pAry駒)
End Function
Public Sub 着手(ByVal arg駒名 As String, _
ByVal arg元位置 As g位置, _
ByVal arg先位置 As g位置, _
ByVal arg先手 As Boolean)
Dim i元行 As Integer, i元列 As Integer
Dim i先行 As Integer, i先列 As Integer
If Not arg元位置 Is Nothing Then '初期配置
i元行 = arg元位置.行: i元列 = arg元位置.列
End If
i先行 = arg先位置.行: i先列 = arg先位置.列
'元位置:-1,-1は初期配置
'位置:0,0は駒台の出し入れ
Dim obj駒 As cls駒
Select Case True
Case arg元位置 Is Nothing '初期配置
Set obj駒 = New cls駒
Set pAry駒(i先行, i先列) = obj駒.駒作成(arg駒名, arg先手, arg先位置)
'棋譜は不要
Exit Sub
Case i先行 = 0 '駒台へ
Set pAry駒(i元行, i元列) = Nothing
'棋譜は不要
Exit Sub
Case i元行 = 0 '駒台から
Set obj駒 = New cls駒
Set pAry駒(i先行, i先列) = obj駒.駒作成(arg駒名, arg先手, arg先位置)
Case Else '駒移動
Set pAry駒(i先行, i先列) = pAry駒(i元行, i元列)
Set pAry駒(i先行, i先列).駒位置 = arg先位置
pAry駒(i先行, i先列).成り = 成り判定(arg元位置, arg先位置)
End Select
'棋譜履歴
pCol棋譜.Add create棋譜(pAry駒(i元行, i元列), pAry駒(i先行, i先列))
'棋譜作成で元位置が必要なので、棋譜作成後のここで消す
Set pAry駒(i元行, i元列) = Nothing
'盤面履歴
pCol盤面.Add pAry駒
Call 手番交代
End Sub
'**********************************************************************
' 非公開メソッド
'**********************************************************************
Private Sub 手番交代()
Me.先手 = Not Me.先手
End Sub
'棋譜の表記方法:https://www.shogi.or.jp/faq/kihuhyouki.html
'棋譜ほMi2形式で作成(▲5ニ銀右上成)
Private Function create棋譜(ByVal arg駒元 As cls駒, _
ByVal arg駒先 As cls駒) As String
Dim ary(1 To 7) As String
ary(1) = IIf(Me.先手, "▲", "△")
ary(2) = StrConv(10 - arg駒先.駒位置.列, vbWide)
ary(3) = WorksheetFunction.Text(arg駒先.駒位置.行, "[DBNum1]0")
ary(4) = arg駒先.表示名称
ary(5) = get駒の相対位置(arg駒先)
ary(6) = get駒の動作(arg駒先)
ary(7) = IIf(arg駒元.成り = arg駒先.成り, "", "成")
create棋譜 = Join(ary, "")
End Function
Public Function 終局判定() As Boolean
'※※※これは難しいので後回し※※※
End Function
Private Function 成り判定(ByRef arg元位置 As g位置, _
ByVal arg先位置 As g位置) As Boolean
'※※※これは難しいので後回し※※※
End Function
Private Function get駒の相対位置(ByVal arg駒先 As cls駒) As String
'※※※これは難しいので後回し※※※
End Function
Private Function get駒の動作(ByVal arg駒先 As cls駒) As String
'※※※これは難しいので後回し※※※
End Function
将棋盤クラスVBAの解説
クラスを配列にいれて処理する部分を理解していただければ十分です。
Private pAry駒(1 To 9, 1 To 9) As cls駒
この使い方を理解してください。
Set 駒移動可能位置 = pAry駒(arg位置.行, arg位置.列).駒移動可能位置(pAry駒)
これは、
pAry駒(arg位置.行, arg位置.列)
これがcls駒の1つのオブジェクトになります。
そして、駒オブジェクトの駒移動可能位置メソッドを呼び出しています。
駒移動可能位置メソッドについて
駒の配置(他の駒の位置が必要)を持っているのは将棋盤クラスですが、駒の動きを管理しているのは駒クラスです。
つまり、将棋盤クラスと駒クラスの共同作業になります。
VBAとしては、どちらに記述しても可能ですが、将棋盤クラスに記述したことで、
pAry駒(arg位置.行, arg位置.列).駒移動可能位置(pAry駒)
このように、駒配置の配列から入って、最後にその配列を引数にいれるという、ちょっと変な感じになってしまっています。
しかし将棋盤クラスでやる場合は、駒クラスから駒の移動に関する情報をもらわないといけないので、どっちにしても面倒な記述になりそうです。
正解が決まっているわけではないので、とりあえずこれで進めていきます。
数値を漢数字に変換
これで算用数字を漢数字に変換しています。
これについては、ツイッターで問題を出した後に回答ページを作成しました。
※※※これは難しいので後回し※※※
・敵陣に入った場合
・敵陣内で動いた場合
・敵陣から外に出た場合
成るか成らないかの確認が必要
左:指す側から見て左側の駒を動かした場合
直:指す側から見て上に駒を動かした場合
打:持駒から打った場合
寄:1マス以上、横に動く
引:1段以上、下に動く
将棋盤クラスのテストVBAコード
Sub test3()
Const 先手 As Boolean = True
Const 後手 As Boolean = False
Dim obj将棋盤 As New cls将棋盤
'大橋流
With obj将棋盤
.着手 "玉", Nothing, 棋譜位置(5, 9), 先手
.着手 "玉", Nothing, 棋譜位置(5, 1), 後手
.着手 "金", Nothing, 棋譜位置(6, 9), 先手
.着手 "金", Nothing, 棋譜位置(4, 1), 後手
.着手 "金", Nothing, 棋譜位置(4, 9), 先手
.着手 "金", Nothing, 棋譜位置(6, 1), 後手
.着手 "銀", Nothing, 棋譜位置(7, 9), 先手
.着手 "銀", Nothing, 棋譜位置(3, 1), 後手
.着手 "銀", Nothing, 棋譜位置(3, 9), 先手
.着手 "銀", Nothing, 棋譜位置(7, 1), 後手
.着手 "桂", Nothing, 棋譜位置(8, 9), 先手
.着手 "桂", Nothing, 棋譜位置(2, 1), 後手
.着手 "桂", Nothing, 棋譜位置(2, 9), 先手
.着手 "桂", Nothing, 棋譜位置(8, 1), 後手
.着手 "香", Nothing, 棋譜位置(9, 9), 先手
.着手 "香", Nothing, 棋譜位置(1, 1), 後手
.着手 "香", Nothing, 棋譜位置(1, 9), 先手
.着手 "香", Nothing, 棋譜位置(9, 1), 後手
.着手 "角", Nothing, 棋譜位置(8, 8), 先手
.着手 "角", Nothing, 棋譜位置(2, 2), 後手
.着手 "飛", Nothing, 棋譜位置(2, 8), 先手
.着手 "飛", Nothing, 棋譜位置(8, 2), 後手
.着手 "歩", Nothing, 棋譜位置(5, 7), 先手
.着手 "歩", Nothing, 棋譜位置(5, 3), 後手
.着手 "歩", Nothing, 棋譜位置(6, 7), 先手
.着手 "歩", Nothing, 棋譜位置(4, 3), 後手
.着手 "歩", Nothing, 棋譜位置(4, 7), 先手
.着手 "歩", Nothing, 棋譜位置(6, 3), 後手
.着手 "歩", Nothing, 棋譜位置(7, 7), 先手
.着手 "歩", Nothing, 棋譜位置(3, 3), 後手
.着手 "歩", Nothing, 棋譜位置(3, 7), 先手
.着手 "歩", Nothing, 棋譜位置(7, 3), 後手
.着手 "歩", Nothing, 棋譜位置(8, 7), 先手
.着手 "歩", Nothing, 棋譜位置(2, 3), 後手
.着手 "歩", Nothing, 棋譜位置(2, 7), 先手
.着手 "歩", Nothing, 棋譜位置(8, 3), 後手
.着手 "歩", Nothing, 棋譜位置(9, 7), 先手
.着手 "歩", Nothing, 棋譜位置(1, 3), 後手
.着手 "歩", Nothing, 棋譜位置(1, 7), 先手
.着手 "歩", Nothing, 棋譜位置(9, 3), 後手
Call PrintArray(.現在盤面)
.着手 "歩", 棋譜位置(2, 7), 棋譜位置(2, 6), 先手
.着手 "歩", 棋譜位置(3, 3), 棋譜位置(3, 4), 後手
.着手 "歩", 棋譜位置(2, 6), 棋譜位置(2, 5), 先手
.着手 "角", 棋譜位置(2, 2), 棋譜位置(3, 3), 後手
.着手 "歩", 棋譜位置(7, 7), 棋譜位置(7, 6), 先手
.着手 "歩", 棋譜位置(8, 3), 棋譜位置(8, 4), 後手
.着手 "歩", 棋譜位置(6, 9), 棋譜位置(7, 8), 後手
Debug.Print ""
Call PrintCollection(.棋譜履歴)
Debug.Print ""
Call PrintArray(.現在盤面)
End With
End Sub
Function 棋譜位置(ByVal arg列 As Integer, ByVal arg行 As Integer) As g位置
Set 棋譜位置 = g位置(arg行, 10 - arg列)
End Function
Sub PrintArray(ByRef ary, Optional separator As String = "")
Dim i As Long, j As Long, str As String
For i = LBound(ary, 1) To UBound(ary, 1)
str = ""
For j = LBound(ary, 2) To UBound(ary, 2)
If j > LBound(ary, 2) Then str = str & separator
str = str & ary(i, j)
Next
Debug.Print str
Next
End Sub
Sub PrintCollection(ByVal argCol As Collection)
Dim v
For Each v In argCol
Debug.Print v
Next
End Sub
駒を並べる順番は関係ありませんが、せっかくなので大橋流で並べてみました。
どのような順番で並べても構いません。
趣味でちょっとやるくらいなら、皆さん適当に並べていると思います。
並べ方の流派というか、プロの先生方の駒の並べる順序はある程度決まっています。
それが、大橋流と伊藤流です。
プロの対局中継を見ていると、ほとんどの先生は大橋流で並べているようです。
そこから7手指して、また、駒配置を出力しています。
棋譜位置
筋は、右から1,2,3,…
段は、上から1,2,3,…
しかし配列は行・列の順で、列は左から数えます。
この変換を行い、位置クラスで返しています。
▲2六歩なら、
(2, 6)→ (4, 2)
将棋盤クラスのテストVBAの結果
香↓桂↓銀↓金↓玉↓金↓銀↓桂↓香↓
飛↓ 角↓
歩↓歩↓歩↓歩↓歩↓歩↓歩↓歩↓歩↓
歩↑歩↑歩↑歩↑歩↑歩↑歩↑歩↑歩↑
角↑ 飛↑
香↑桂↑銀↑金↑玉↑金↑銀↑桂↑香↑
▲2六歩
△3四歩
▲2五歩
△3三角
▲7六歩
△8四歩
▲7八金
香↓桂↓銀↓金↓玉↓金↓銀↓桂↓香↓
飛↓
歩↓ 歩↓歩↓歩↓歩↓角↓歩↓歩↓
歩↓ 歩↓
歩↑
歩↑
歩↑歩↑ 歩↑歩↑歩↑歩↑ 歩↑
角↑金↑ 飛↑
香↑桂↑銀↑ 玉↑金↑銀↑桂↑香↑
Excel将棋の目次
新着記事NEW ・・・新着記事一覧を見る
付録:AI×VBA実践リソース集|生成AI活用研究(2025-05-25)
おわりに:AI×VBAはあなたの未来を変える強力な武器|生成AI活用研究(2025-05-25)
第7章:さらなる高みへ!AI×VBA応用テクニックと未来への備え|生成AI活用研究(2025-05-24)
第6章:AIとVBAを学び続ける!あなたの「超効率化」を止めないヒント|生成AI活用研究(2025-05-22)
第5章:AI×VBAでつまづかない!トラブルシューティングとAIとの付き合い方
|生成AI活用研究(2025-05-21)
第4章:【事例で学ぶ】AIとVBAでExcel作業を劇的に効率化する!
|生成AI活用研究(2025-05-20)
第3章:AIを「自分だけのVBA先生」にする!質問・相談の超実践テクニック|生成AI活用研究(2025-05-19)
第2章 VBAって怖くない!Excelを「言葉で動かす」(超入門)|生成AI活用研究(2025-05-18)
第1章:AIって一体何?あなたのExcel作業をどう変える?(AI超基本)|生成AI活用研究(2025-05-18)
AI時代のExcel革命:AI×VBAで“書かない自動化”超入門|生成AI活用研究(2025-05-17)
アクセスランキング ・・・ ランキング一覧を見る
1.最終行の取得(End,Rows.Count)|VBA入門
2.繰り返し処理(For Next)|VBA入門
3.変数宣言のDimとデータ型|VBA入門
4.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
5.ひらがな⇔カタカナの変換|エクセル基本操作
6.RangeとCellsの使い方|VBA入門
7.メッセージボックス(MsgBox関数)|VBA入門
8.セルのクリア(Clear,ClearContents)|VBA入門
9.FILTER関数(範囲をフィルター処理)|エクセル入門
10.条件分岐(Select Case)|VBA入門
- ホーム
- マクロVBA応用編
- マクロVBAサンプル集
- Excel将棋:将棋盤クラスの作成&単体テスト(№7)
このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
記述には細心の注意をしたつもりですが、
間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。
掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。