概要
Excel VBAを用いて将棋プログラムを開発する際、避けては通れない最重要課題が「禁じ手(反則手)の判定」です。将棋はルールが非常に厳格であり、二歩、打ち歩詰め、王手放置、千日手など、考慮すべき判定項目は多岐にわたります。本稿では、VBAという非力な環境下でいかに効率的かつ高速にこれらを判定するか、そのアルゴリズムの核心部分を解説します。特に、パフォーマンスを維持しつつ複雑な盤面状態をどう評価するか、プロフェッショナルな視点からコードを紐解いていきます。
詳細解説
禁じ手判定を実装する上で最も重要な概念は「盤面の状態をどう保持するか」です。単にセルに値を格納するだけでなく、二次元配列やクラスオブジェクトを活用して、現在の手番における「王の位置」や「利き(攻撃範囲)」を瞬時に計算できる状態にしておく必要があります。
特に「王手放置」の判定は難易度が高いです。ある手を指した直後に、自分の王が相手の駒の利きにさらされていないかを確認する必要があります。これを素朴に「全駒の利きを再計算する」というアプローチで行うと、VBAの実行速度では重すぎて使い物になりません。そこで重要となるのが、「差分更新」の考え方です。駒が動いた前後の変化だけを追跡し、王の周囲の危険度を動的に評価する設計が求められます。
また、「二歩」の判定は列ごとの歩の数をカウントするだけで済みますが、「打ち歩詰め」は非常に複雑です。持ち駒の歩を打った瞬間、相手の王が逃げ場を失い、かつその詰みが「歩を打ったこと」によってのみ成立しているかを確認する再帰的な評価が必要です。
サンプルコード
以下に、禁じ手判定の中核をなす「二歩判定」と「王手放置判定」の基本的なサンプルコードを示します。
' 禁じ手判定メインプロシージャ
Public Function IsForbiddenMove(ByVal board As Variant, ByVal fromRow As Integer, ByVal fromCol As Integer, ByVal toRow As Integer, ByVal toCol As Integer, ByVal player As Integer) As Boolean
' 1. 二歩判定(先行・後攻別に判定)
If IsNifu(board, toCol, player) Then
MsgBox "禁じ手:二歩です。"
IsForbiddenMove = True
Exit Function
End If
' 2. 王手放置判定(仮想盤面を作成して検証)
If IsKingCheckedAfterMove(board, fromRow, fromCol, toRow, toCol, player) Then
MsgBox "禁じ手:王手放置です。"
IsForbiddenMove = True
Exit Function
End If
IsForbiddenMove = False
End Function
' 二歩判定ロジック
Private Function IsNifu(ByVal board As Variant, ByVal col As Integer, ByVal player As Integer) As Boolean
Dim r As Integer, count As Integer
count = 0
For r = 1 To 9
' 盤面上の駒が「歩」かつ「自分の歩」であるか判定
If board(r, col) = "歩" And player = 1 Then count = count + 1
If board(r, col) = "と" And player = 1 Then ' 実際は「と」は二歩に含まれないが例示
End If
Next r
IsNifu = (count > 0)
End Function
' 王手放置判定の簡略版ロジック
Private Function IsKingCheckedAfterMove(ByVal board As Variant, ByVal fr As Integer, ByVal fc As Integer, ByVal tr As Integer, ByVal tc As Integer, ByVal player As Integer) As Boolean
' 仮想的に駒を動かす
Dim tempBoard As Variant
tempBoard = board
tempBoard(tr, tc) = tempBoard(fr, fc)
tempBoard(fr, fc) = "空"
' 王の位置を特定し、相手の利きがあるかチェック(実際には利き計算関数を呼び出す)
Dim kr As Integer, kc As Integer
' ...王の座標取得処理...
' IsUnderAttack関数は、指定座標が敵の利きにあるかを判定する関数(別定義)
IsKingCheckedAfterMove = IsUnderAttack(tempBoard, kr, kc, player)
End Function
実務アドバイス
VBAで将棋エンジンを開発する際、最も陥りやすい罠は「処理の肥大化」です。判定処理をすべて単一のモジュールに詰め込むのではなく、必ず「盤面管理クラス」「利き計算モジュール」「判定ルールクラス」に責務を分離してください。
また、デバッグ時の視覚化も不可欠です。イミディエイトウィンドウに盤面を表示するだけでなく、条件付き書式を活用して、禁じ手判定時にどの駒が原因で反則となったかをセル色でハイライトする仕組みを組み込むと、開発効率が劇的に向上します。
さらに、パフォーマンスを追求するのであれば、Variant型の多用は避け、配列の宣言時は `Dim board(1 To 9, 1 To 9) As String` のように型を明示してください。また、`DoEvents`を適切なタイミングで挿入することで、長時間計算によるExcelのフリーズを回避し、ユーザー体験を損なわない設計を心がけましょう。
まとめ
VBAによる禁じ手判定の実装は、単なるプログラミングスキルの証明にとどまらず、論理的思考力とアルゴリズム設計の深さを問われる高度なプロジェクトです。今回紹介した二歩判定や王手放置の考え方をベースに、千日手や打ち歩詰めといった難解なルールを一つずつ積み上げていくことで、堅牢な将棋エンジンが完成します。
Excelは単なる表計算ソフトではありません。VBAという強力なエンジンを駆使すれば、今回のような複雑なゲームロジックも十分に実装可能です。この「将棋エンジン開発」を通じて、ぜひ配列操作や再帰処理の極意を体得してください。次回のステップとしては、持ち駒管理機能の実装と、それを踏まえた「詰み」の自動判定アルゴリズムへの挑戦をお勧めします。常に「効率的か」「可読性は高いか」「拡張性はあるか」を自問自答し、プロフェッショナルなコードを追求し続けてください。
