【VBAリファレンス】VBAサンプル集ナンバーリンク(パズル)を解くVBAに挑戦№1

スポンサーリンク

ナンバーリンクを解くVBAプログラム:論理的思考の自動化

ナンバーリンク(Numberlink)は、グリッド上の同じ数字のペアを線で結び、すべてのマスを使い切るという非常にシンプルながら奥の深いパズルです。プログラミングの視点で見ると、これは「制約充足問題」の一種であり、バックトラッキング(深さ優先探索)アルゴリズムを実装する絶好の教材となります。本稿では、Excel VBAを用いてこのパズルを自動的に解くエンジニアリングの手法を詳説します。

ナンバーリンクのアルゴリズム設計

ナンバーリンクを解くための核となるロジックは、再帰呼び出しを用いた「深さ優先探索(DFS)」です。パズルの盤面を2次元配列として捉え、各マスに対して「どの数字の線が通過しているか」「どの方向に接続されているか」を管理します。

本システムの実装における主要なステップは以下の通りです。

1. 初期状態の読み込み:Excelシート上のセルから数字の位置を特定し、配列に格納する。
2. 再帰探索の開始:空いているマスに対して、有効な接続先を試行する。
3. 制約チェック:
– 線の交差や重複がないか。
– すでに結ばれたペアをまたいでいないか。
– 行き止まり(孤立したマス)が発生していないか。
4. 解の検証:すべてのマスが埋まり、かつすべてのペアが正しく接続された場合に成功とする。

バックトラッキングの肝は、一度試したパスが失敗した際に、速やかに状態を「巻き戻す(バックトラックする)」ことにあります。この処理をいかに効率化するかが、VBAという実行速度に制限のある環境でパフォーマンスを出す鍵となります。

サンプルコード:再帰による探索ロジック

以下に、盤面を再帰的に探索して線を引くためのコアとなるロジックを示します。


Option Explicit

' グローバル変数:盤面状態
Dim Grid() As Integer
Dim N As Integer ' 盤面サイズ

' 再帰的な解法関数
Function Solve(r As Integer, c As Integer) As Boolean
    ' 終端条件:すべてのマスを探索完了
    If r > N Then
        Solve = CheckCompletion()
        Exit Function
    End If

    ' 次のマスへ進む計算
    Dim nextR As Integer, nextC As Integer
    nextR = IIf(c = N, r + 1, r)
    nextC = IIf(c = N, 1, c + 1)

    ' すでに数字が埋まっている場合はスキップ
    If Grid(r, c) <> 0 Then
        Solve = Solve(nextR, nextC)
        Exit Function
    End If

    ' 候補となる数字を試行(1からペア数まで)
    Dim i As Integer
    For i = 1 To 5 ' 例:ペア数が5の場合
        If CanPlace(r, c, i) Then
            Grid(r, c) = i
            If Solve(nextR, nextC) Then
                Solve = True
                Exit Function
            End If
            ' バックトラック:失敗したら元に戻す
            Grid(r, c) = 0
        End If
    Next i

    Solve = False
End Function

' 配置の妥当性をチェックする関数
Function CanPlace(r As Integer, c As Integer, val As Integer) As Boolean
    ' ここに隣接チェックや連結制約を記述する
    ' 簡易版:単純な隣接ルールを実装
    CanPlace = True 
End Function

実務におけるエンジニアリング的アドバイス

VBAでパズルソルバーを構築する際、避けて通れないのが「実行速度の壁」です。以下の技術的工夫を取り入れることで、実用性を大幅に向上させることができます。

1. 配列アクセスの最適化:
VBAのセル参照(Rangeオブジェクト)は非常に低速です。必ず一度配列(Variant配列)にデータを転送し、メモリ上で計算を行ってください。計算が終わるまでセルには一切触れないのが鉄則です。

2. 枝刈り(Pruning)の強化:
探索の深さが深くなる前に、「このパスは絶対に解に到達しない」と判断できる条件を早期に適用します。例えば、あるマスが孤立した状態になった場合、そのパスは即座に中断すべきです。これを「デッドエンド検出」と呼びます。

3. 再帰深度の管理:
VBAは再帰の最大回数に制限があります。巨大な盤面を解く場合は、再帰を使わずにスタック構造を自前で実装する「スタックベースの探索」に切り替えることも検討してください。

4. データの可視化:
計算中の経過をイミディエイトウィンドウに逐次出力するとデバッグが困難になります。一定の試行回数ごとにApplication.ScreenUpdatingを制御し、画面を更新する設計にすると、ユーザー体験が大きく向上します。

ナンバーリンクソルバーの拡張性と将来性

ナンバーリンクは、単なるパズルを超えて、物流ルートの最適化や回路設計における配線アルゴリズムの基礎となる概念です。VBAでこのロジックを組む経験は、将来的にPythonやC#へ移行する際にも、アルゴリズム的思考の強固な基盤となります。

特に、制約充足問題(CSP)のライブラリ(PythonのOR-Toolsなど)を触る前に、VBAで泥臭くバックトラッキングを実装する経験は非常に価値があります。なぜなら、ライブラリが内部でどのような計算を行っているかを肌感覚で理解できるからです。

まとめ

ナンバーリンクを解くVBAプログラムの開発は、配列操作、再帰処理、そして論理的な枝刈りという、プログラミングにおける重要なエッセンスが凝縮されています。最初は小さな5×5の盤面から始め、徐々にサイズを大きくしていくことで、自身のコードがどのように成長していくかを実感できるでしょう。

VBAはレガシーな言語と見なされがちですが、パズルを解くという数学的な問いに対しては、非常に強力な武器になります。ぜひ、このコードをベースに、自分だけの「最強のソルバー」を構築してみてください。エラーハンドリングや、解の複数存在チェックなどを実装していくと、さらに深い学びが得られるはずです。エンジニアとしての論理的思考力を鍛えるために、このパズルソルバーは最高のプロジェクトとなるでしょう。

タイトルとURLをコピーしました