はじめに:Excel VBAで将棋の棋譜を視覚化する楽しさ
Excel VBAを使いこなせると、単なるデータ集計や自動化ツール作成にとどまらず、趣味の世界にも応用できることが数多くあります。今回は、将棋の棋譜という、ある種「データ」とも言える情報を、より直感的で分かりやすい形で表示する VBA サンプル集をお届けします。将棋盤を模したユーザーフォーム上に、一手一手駒の動きを表示していくことで、対局の流れを視覚的に追体験できるようになります。これは、将棋の棋譜を記録・分析したい方、あるいは VBA でインタラクティブなアプリケーションを作成してみたい方にとって、非常に興味深いテーマとなるでしょう。本記事では、その基本的な仕組みから、具体的なコード、そして実務で役立つ応用例まで、網羅的に解説していきます。
将棋の棋譜データとは?
まず、VBA で将棋の棋譜を扱う上で、棋譜データがどのような形式で存在するかを理解する必要があります。将棋の棋譜は、一般的に「KIF形式」や「CSA形式」といったテキストベースのフォーマットで記録されます。これらの形式は、各手番のプレイヤー、使用した駒の種類、打った場所、成ったかどうかなどの情報を、人間が読める形式で記述しています。
例えば、KIF形式では以下のような記述になります。
1. ▲7六歩
2. △3四歩
3. ▲2二角成
この例では、「1手目、▲(先手)が7六に歩を打った」「2手目、△(後手)が3四に歩を打った」「3手目、▲が2二に角を打って成った」という意味になります。
CSA形式は、よりコンピュータフレンドリーな記述形式で、例えば `00000 00000 R+0022` のような形式で表現されます。
本記事で扱うサンプルでは、これらの形式を直接解析するのではなく、より扱いやすいように、あらかじめ配列やリスト形式に変換したデータを使用することを想定します。これは、VBA で外部ファイルを直接パースするのは複雑になりがちであるため、学習のしやすさを優先するためです。
ユーザーフォームで将棋盤を再現する
将棋の棋譜を視覚化する上で、最も直感的な方法は、将棋盤を模したインターフェースを用意することです。ここでは、Excel の「ユーザーフォーム」機能を利用して、将棋盤を再現します。
ユーザーフォームの設計
ユーザーフォーム上に将棋盤を表現するために、以下の要素を配置します。
* **駒の表示エリア:** 各マス目に駒を表示するためのコントロールが必要です。ここでは、`Label` コントロールを 81 個配置し、それぞれの `Caption` プロパティに駒の名前(例: ” ▲歩”, ” △桂”)を表示させる方法を考えます。または、より高度な表現をするために、`Image` コントロールを使用して駒の画像を表示することも可能です。
* **手番表示:** 現在どちらの手番かを示すための `Label` コントロール。
* **棋譜表示エリア:** 進行中の棋譜の履歴を表示するための `ListBox` コントロールや `TextBox` コントロール。
* **操作ボタン:** 「次の一手」「前の手」「再生」「停止」などの操作を行うための `CommandButton` コントロール。
ユーザーフォームの設計は、見た目の美しさだけでなく、操作性も考慮して行うことが重要です。将棋盤のマス目は 9×9 なので、`Label` コントロールを 81 個配置するのは手作業では大変です。VBA のコードを使って動的に生成する方法も有効です。
駒の配置と移動の表現
ユーザーフォーム上の将棋盤で駒を表現する際、各マスに対応する `Label` コントロールを配列で管理すると便利です。例えば、`Dim lblBoard(1 To 9, 1 To 9) As MSForms.Label` のように宣言し、フォームのロード時に各コントロールを生成・配置します。
駒の移動を表現するには、元のマスの `Label` の `Caption` をクリアし、移動先のマスの `Label` に `Caption` を設定します。駒が成る場合は、`Caption` の内容を変更(例: “▲歩” を “▲と” に)します。
サンプルコード:棋譜をユーザーフォームに表示するVBAプログラム
それでは、実際に将棋の棋譜データを読み込み、ユーザーフォーム上の将棋盤に一手ずつ表示していく VBA コードの例を見ていきましょう。
このサンプルでは、簡略化のため、棋譜データは VBA コード内の配列として直接定義しています。実際のアプリケーションでは、外部ファイル(KIF形式など)から読み込む処理を追加する必要があります。
**ユーザーフォームのモジュール (UserForm1)**
Option Explicit
‘ 将棋盤のLabelコントロールを格納する配列
Dim lblBoard(1 To 9, 1 To 9) As MSForms.Label
‘ 現在表示している棋譜のインデックス
Dim currentMoveIndex As Integer
‘ 棋譜データ(例:KIF形式風の簡易表現)
Dim gameMoves As Variant
‘ 駒の表示名と内部的な値のマッピング(簡易版)
Private Function GetPieceDisplay(pieceValue As String, player As String) As String
Dim pieceChar As String
pieceChar = Left(pieceValue, 1) ‘ 例: “歩”, “香”, “桂”, “銀”, “金”, “角”, “飛”, “玉”, “と”, “杏”, “圭”, “銀”, “金”, “馬”, “竜”
Select Case pieceChar
Case “歩”: GetPieceDisplay = ” ▲歩”
Case “香”: GetPieceDisplay = ” ▲香”
Case “桂”: GetPieceDisplay = ” ▲桂”
Case “銀”: GetPieceDisplay = ” ▲銀”
Case “金”: GetPieceDisplay = ” ▲金”
Case “角”: GetPieceDisplay = ” ▲角”
Case “飛”: GetPieceDisplay = ” ▲飛”
Case “玉”: GetPieceDisplay = ” ▲玉”
Case “と”: GetPieceDisplay = ” ▲と”
Case “杏”: GetPieceDisplay = ” ▲杏”
Case “圭”: GetPieceDisplay = ” ▲圭”
Case “銀”: GetPieceDisplay = ” ▲銀” ‘ 成銀は一旦同じ表示とする(簡易化)
Case “金”: GetPieceDisplay = ” ▲金” ‘ 成金は一旦同じ表示とする(簡易化)
Case “馬”: GetPieceDisplay = ” ▲馬”
Case “竜”: GetPieceDisplay = ” ▲竜”
Case Else
GetPieceDisplay = ” ” ‘ 空白
End Select
If player = “△” Then
GetPieceDisplay = Replace(GetPieceDisplay, ” ▲”, ” △”)
End If
End Function
‘ 盤上の駒を初期化する
Private Sub InitializeBoard()
Dim i As Integer, j As Integer
Dim lbl As MSForms.Label
‘ 盤のLabelコントロールを生成・配置
For i = 1 To 9
For j = 1 To 9
Set lbl = Me.Controls.Add(“Forms.Label”, “lbl” & i & “_” & j, True)
With lbl
.Top = (i – 1) * 30 + 20 ‘ マスのY座標
.Left = (j – 1) * 40 + 20 ‘ マスのX座標
.Width = 40
.Height = 30
.BorderStyle = vbBSNone ‘ 枠線なし
.TextAlign = fmTextAlignCenter
.Font.Bold = True
.Caption = “” ‘ 初期は空白
Set lblBoard(i, j) = lbl
End With
Next j
Next i
‘ 盤の区切り線などを描画することも可能だが、ここでは省略
End Sub
‘ 駒の配置を初期状態に戻す
Private Sub ResetPieces()
Dim i As Integer, j As Integer
For i = 1 To 9
For j = 1 To 9
lblBoard(i, j).Caption = “”
Next j
Next i
End Sub
‘ 指定された棋譜データに基づいて盤面を更新する
Private Sub UpdateBoard(moveData As Variant)
Dim i As Integer, j As Integer
Dim fromRow As Integer, fromCol As Integer
Dim toRow As Integer, toCol As Integer
Dim piece As String
Dim player As String
Dim promoted As Boolean
‘ 盤面を一旦リセット
ResetPieces
‘ 棋譜データを解析して駒を配置
‘ moveData の形式例: Array(“▲”, “歩”, “76”) -> ▲歩を7六に配置
‘ moveData の形式例: Array(“△”, “飛”, “83”) -> △飛を8三に配置
‘ moveData の形式例: Array(“▲”, “角”, “22”, True) -> ▲角を2二に成って配置
‘ moveData の形式例: Array(“△”, “歩”, “14”) -> △歩を1四に配置 (打ち歩)
‘ moveData の形式例: Array(“▲”, “歩”, “14”, “34”) -> ▲歩を3四に移動
player = moveData(0)
piece = moveData(1)
promoted = False
If UBound(moveData) >= 3 Then
‘ 移動の場合
Dim fromPosStr As String, toPosStr As String
fromPosStr = moveData(2)
toPosStr = moveData(3)
‘ 座標変換 (例: “76” -> row=3, col=7)
‘ 将棋盤の座標系は、通常、上から1, 下に9、右から1、左に9。
‘ VBAの配列は1から始まるため、変換に注意。
‘ ここでは、KIF形式の「段」「筋」を想定した変換を行う。
‘ 段(横方向): 1-9 -> VBA配列の行 (上から1行目=1, 下から9行目=9)
‘ 筋(縦方向): 1-9 -> VBA配列の列 (右から1列目=1, 左から9列目=9)
‘ 棋譜の表記例: ▲7六歩 -> 先手(▲)が7筋(右から7列目)の6段目(上から6行目)に歩を打つ
‘ ユーザーフォームの配列lblBoard(row, col) に合わせる
‘ 棋譜の「段」をY座標、棋譜の「筋」をX座標と考える。
‘ 棋譜の「段」は上から1~9。VBA配列の行は上から1~9。
‘ 棋譜の「筋」は右から1~9。VBA配列の列は右から1~9。
‘ したがって、KIFの「段」-> lblBoardの行、KIFの「筋」-> lblBoardの列 となる。
‘ 座標文字列の解析 (例: “76” -> 段7, 筋6)
Dim dan As Integer, suji As Integer
dan = CInt(Mid(toPosStr, 1, 1))
suji = CInt(Mid(toPosStr, 2, 1))
toRow = dan
toCol = suji
‘ 移動元座標の解析
dan = CInt(Mid(fromPosStr, 1, 1))
suji = CInt(Mid(fromPosStr, 2, 1))
fromRow = dan
fromCol = suji
‘ 移動元のLabelのCaptionをクリア
lblBoard(fromRow, fromCol).Caption = “”
‘ 移動先のLabelに駒を表示
If UBound(moveData) >= 4 Then
‘ 成り駒の場合
If moveData(4) = True Then
promoted = True
‘ 成駒の表示名を取得(簡易化のため、ここでは成る前の駒名から推測)
piece = GetPromotedPiece(piece) ‘ 成る前の駒名から成駒名を返す関数を別途定義
End If
End If
lblBoard(toRow, toCol).Caption = GetPieceDisplay(piece, player)
Else
‘ 持ち駒の打ち歩の場合 (簡易化のため、ここでは打ち歩のみ対応)
‘ 打ち歩の場合、移動元はなく、打つ場所のみ指定される
Dim posStr As String
posStr = moveData(2)
‘ 座標文字列の解析
Dim dan As Integer, suji As Integer
dan = CInt(Mid(posStr, 1, 1))
suji = CInt(Mid(posStr, 2, 1))
toRow = dan
toCol = suji
‘ 打つ場所のLabelに駒を表示
lblBoard(toRow, toCol).Caption = GetPieceDisplay(piece, player)
End If
End Sub
‘ 成駒の名称を返す(簡易版)
Private Function GetPromotedPiece(originalPiece As String) As String
Select Case originalPiece
Case “歩”: GetPromotedPiece = “と”
Case “香”: GetPromotedPiece = “杏”
Case “桂”: GetPromotedPiece = “圭”
Case “銀”: GetPromotedPiece = “全” ‘ 成銀は「全」
Case “角”: GetPromotedPiece = “馬”
Case “飛”: GetPromotedPiece = “竜”
Case Else: GetPromotedPiece = originalPiece ‘ 金、玉は成らない
End Select
End Function
‘ ユーザーフォームが初期化されたときの処理
Private Sub UserForm_Initialize()
currentMoveIndex = -1 ‘ 初期状態は棋譜の開始前
Me.Caption = “Excel将棋 ~ 棋譜表示 (№12)”
‘ 駒の表示エリアを生成
InitializeBoard
‘ サンプル棋譜データをロード
‘ 形式: Array(player, piece, fromPos, toPos, Optional promoted) または Array(player, piece, toPos) for drop
‘ “76” -> 7段6筋 (上から7行目、右から6列目)
gameMoves = Array( _
Array(“▲”, “歩”, “76”), _
Array(“△”, “歩”, “34”), _
Array(“▲”, “歩”, “77”), _
Array(“△”, “歩”, “33”), _
Array(“▲”, “歩”, “78”), _
Array(“△”, “歩”, “32”), _
Array(“▲”, “歩”, “79”), _
Array(“△”, “歩”, “31”), _
Array(“▲”, “歩”, “66”), _
Array(“△”, “歩”, “44”), _
Array(“▲”, “角”, “88”), _
Array(“△”, “角”, “22”), _
Array(“▲”, “飛”, “28”), _
Array(“△”, “飛”, “82”), _
Array(“▲”, “銀”, “79”), _
Array(“△”, “銀”, “31”), _
Array(“▲”, “金”, “69”), _
Array(“△”, “金”, “41”), _
Array(“▲”, “桂”, “97”), _
Array(“△”, “桂”, “13”), _
Array(“▲”, “香”, “99”), _
Array(“△”, “香”, “11”), _
Array(“▲”, “玉”, “59”), _
Array(“△”, “玉”, “51”), _
Array(“▲”, “歩”, “67”), _
Array(“△”, “歩”, “43”), _
Array(“▲”, “歩”, “77”), _
Array(“△”, “歩”, “33”), _
Array(“▲”, “歩”, “78”), _
Array(“△”, “歩”, “32”), _
Array(“▲”, “歩”, “79”), _
Array(“△”, “歩”, “31”), _
Array(“▲”, “歩”, “68”), _
Array(“△”, “歩”, “42”), _
Array(“▲”, “歩”, “57”), _
Array(“△”, “歩”, “53”), _
Array(“▲”, “歩”, “47”), _
Array(“△”, “歩”, “63”), _
Array(“▲”, “歩”, “37”), _
Array(“△”, “歩”, “73”), _
Array(“▲”, “歩”, “27”), _
Array(“△”, “歩”, “83”), _
Array(“▲”, “歩”, “17”), _
Array(“△”, “歩”, “93”), _
Array(“▲”, “角”, “86”), _
Array(“△”, “角”, “24”), _
Array(“▲”, “飛”, “26”), _
Array(“△”, “飛”, “84”), _
Array(“▲”, “銀”, “77”), _
Array(“△”, “銀”, “33”), _
Array(“▲”, “金”, “67”), _
Array(“△”, “金”, “43”), _
Array(“▲”, “桂”, “95”), _
Array(“△”, “桂”, “15”), _
Array(“▲”, “香”, “98”), _
Array(“△”, “香”, “12”), _
Array(“▲”, “玉”, “58”), _
Array(“△”, “玉”, “52”), _
Array(“▲”, “歩”, “69”), _
Array(“△”, “歩”, “41”), _
Array(“▲”, “角”, “85”), _
Array(“△”, “角”, “25”), _
Array(“▲”, “飛”, “27”), _
Array(“△”, “飛”, “83”), _
Array(“▲”, “銀”, “78”), _
Array(“△”, “銀”, “32”), _
Array(“▲”, “金”, “68”), _
Array(“△”, “金”, “42”), _
Array(“▲”, “桂”, “96”), _
Array(“△”, “桂”, “14”), _
Array(“▲”, “香”, “99”), _
Array(“△”, “香”, “11”), _
Array(“▲”, “玉”, “57”), _
Array(“△”, “玉”, “53”), _
Array(“▲”, “歩”, “76”), _
Array(“△”, “歩”, “34”), _
Array(“▲”, “歩”, “75”), _
Array(“△”, “歩”, “35”), _
Array(“▲”, “歩”, “74”), _
Array(“△”, “歩”, “36”), _
Array(“▲”, “歩”, “73”), _
Array(“△”, “歩”, “37”), _
Array(“▲”, “歩”, “72”), _
Array(“△”, “歩”, “38”), _
Array(“▲”, “歩”, “71”), _
Array(“△”, “歩”, “39”), _
Array(“▲”, “歩”, “66”), _
Array(“△”, “歩”, “44”), _
Array(“▲”, “歩”, “65”), _
Array(“△”, “歩”, “45”), _
Array(“▲”, “歩”, “64”), _
Array(“△”, “歩”, “46”), _
Array(“▲”, “歩”, “63”), _
Array(“△”, “歩”, “47”), _
Array(“▲”, “歩”, “62”), _
Array(“△”, “歩”, “48”), _
Array(“▲”, “歩”, “61”), _
Array(“△”, “歩”, “49”), _
Array(“▲”, “歩”, “56”), _
Array(“△”, “歩”, “54”), _
Array(“▲”, “歩”, “55”), _
Array(“△”, “歩”, “54”), _
Array(“▲”, “歩”, “53”), _
Array(“△”, “歩”, “55”), _
Array(“▲”, “歩”, “52”), _
Array(“△”, “歩”, “56”), _
Array(“▲”, “歩”, “51”), _
Array(“△”, “歩”, “57”), _
Array(“▲”, “歩”, “46”), _
Array(“△”, “歩”, “64”), _
Array(“▲”, “歩”, “45”), _
Array(“△”, “歩”, “65”), _
Array(“▲”, “歩”, “44”), _
Array(“△”, “歩”, “66”), _
Array(“▲”, “歩”, “43”), _
Array(“△”, “歩”, “67”), _
Array(“▲”, “歩”, “42”), _
Array(“△”, “歩”, “68”), _
Array(“▲”, “歩”, “41”), _
Array(“△”, “歩”, “69”), _
