基礎から学ぶVBAプログラミング教室

もりさんのお題を解きながら楽しく勉強しよう

スポンサーリンク

【連載】VBAでナンプレ(数独)を解いてみよう②<共通部品>

VBAでナンプレを解いてみようシリーズ【第2回目】です。

f:id:excel-accounting:20180511135041p:plain:w400

連載記事の一覧はこちら→【VBAナンプレ連載】


今回もノンプログラマーによるノンプログラマーのためのやさしい解説付きですよ。

f:id:excel-accounting:20180424002011p:plain:w150

前回のおさらい

前回は、マクロ全体に関わる[全体処理]を作成しましたね。

変数をもう一度おさらいしておきましょう。

f:id:excel-accounting:20180531162017p:plain

【定義】 ※rとcはパブリック変数とします。

変数名
データ型
意味
PuzzleArea
Rangeオブジェクト パズル全体の9×9のエリア
BlockArea
Rangeオブジェクト PuzzleAreaの中の3×3エリア
r
Long型 9×9のエリアの番号
c
Long型 9×9のエリアの番号

共通部品の作成

今回の記事では、全体処理・解法1~3で共通する処理を[共通部品]として作成します。

みんなから呼ばれるクラスの人気者みたいな存在です。

f:id:excel-accounting:20180601091609p:plain:w400


(まだ解法1~3を作ってないのに、「共通する処理」なんてわからないよ・・・)

って思いますよね。


私はこの2ステップで作成しました。

  • ステップ1.解法1~3を別々に作成
  • ステップ2.同じ処理(似たような処理)を部品化

ステップ1~2で試行錯誤をかなり繰り返したのですが、この過程を記事に書くと混乱させてしまうので、先に共通部品を紹介する流れにします。


[共通部品]にはFunctionプロシージャもありますので、

(Functionプロシージャってなに?)

という方は、こちらの記事で理解を深めていただくと今後の連載がスムーズに読めますよ。

Functionプロシージャとは?

共通部品1(BlockArea特定処理)

解法1~3を解くためには、現在地がどこのBlockAreaに所属しているかがポイントになってきます。

BlockAreaとは、パズル全体に9個存在する「3×3のエリア」です。

f:id:excel-accounting:20180520225701p:plain:w300


現在地の情報をもとに、所属する3×3エリア(BlockArea)を特定する処理を作成します。


1.BlockAreaの特定方法

現在地の【行番号】と【列番号】から、3×3エリアの「始点セル」の【行番号】と【列番号】を特定します。

新しい変数を2つ用意します。 ※r1とc1はパブリック変数とします。

変数名
データ型
定義
r1
Long型 3×3エリアの始点セルの【行番号】
c1
Long型 3×3エリアの始点セルの【列番号】

【イメージ図】
f:id:excel-accounting:20180526211654p:plain:w350

【例】現在地 が Cells(5, 5)の場合

  • 始点セル = Cells(4, 4)
  • 終点セル = Cells(4 + 2, 4 + 2)
  • BlockArea = Range(Cells(4, 4),Cells(4 + 2, 4 + 2))

★ポイント★
BlockAreaの終点セルは特定しません。
セル範囲はすべて3×3のため、【始点セル】+2で終点セルが求まるからです。


BlockArea「始点セル」の一覧

f:id:excel-accounting:20180527175624p:plain:w400

この一覧からみえてくる規則性です。

現在地の行番号(r
始点セルの行番号(r1
1,2,3の場合
1
4,5,6の場合
4
7,8,9の場合
7

※列番号も同様の規則

この規則性を利用してFunctionプロシージャを作成します。


2.始点セルの特定処理

【概要】

  1. プロシージャ名(Function)
    • SearchBlockArea
  2. 処理内容
    • 現在地の行番号/列番号から、3×3エリアの「始点セル」の行番号/列番号を特定する
  3. 用意する変数(Long型)
    • x
  4. 返り値(Long型)
    • BlockAreaの始点セルの【行番号】または【列番号】


【イメージ】
f:id:excel-accounting:20180602000536p:plain:w450


【コード】

Function SearchBlockArea(x As Long) As Long
'-------------------------------------------------------------------
' * 機能:BlockArea(3×3のエリア)の始点セルを特定する
' * 引数:PuzzleAreaの【行番号(r)】または【列番号(c)】
' * 返り値:BlockArea上端の行番号(r1)または左端の列番号(c1)
'-------------------------------------------------------------------

    Select Case x
        
        Case 1, 4, 7
            SearchBlockArea = x
        Case 2, 5, 8
            SearchBlockArea = x - 1
        Case 3, 6, 9
            SearchBlockArea = x - 2

    End Select

End Function


3.呼び出す側の処理

この[SearchBlockArea]は[全体処理]から呼び出します。

  • 行番号 r を渡し、返り値を r1 に格納
  • 列番号 c を渡し、返り値を c1 に格納

f:id:excel-accounting:20180520224539p:plain:w150

For r = 1 To 9 '【ループ2】開始
    For c = 1 To 9

        r1 = SearchBlockArea(r)
        c1 = SearchBlockArea(c)

        '-------------------------------
        'ここで解読処理(解法1~3)
        '-------------------------------
            
    Next c
Next r

現在地が所属するBlockAreaを特定してから、解法1~3に進みます。
f:id:excel-accounting:20180527160046p:plain

共通部品2(数字検索処理)

[指定のセル範囲]にnumが存在するか検索し、あり/なしの結果を返すFunctionプロシージャです。
※num=数字の1~9(パブリック変数)

【概要】

  1. プロシージャ名(Function)
    • isExistNum
  2. 処理内容
    • [指定のセル範囲]にnumが存在するか検索し、検索結果を返す
  3. 用意する変数(Long型)
    • y1, x1, y2, x2
  4. 返り値(Boolean型)
    • 数字が存在する場合:True
    • 数字が存在しない場合:False

受け取った4つの引数で検索範囲を設定します。
Range(Cells(y1, x1), Cells(y2, x2))


【イメージ】
f:id:excel-accounting:20180601095420p:plain:w450


【コード】

Function isExistNum _
    (ByVal y1 As Long, x1 As Long, y2 As Long, x2 As Long) As Boolean
' --------------------------------------------------------------------------
' * 機能:[指定のセル範囲]にnumが存在するか検索する
' * 引数:始点セルの【行番号】,【列番号】と終点セルの【行番号】,【列番号】
' * 返り値:numが見つかった場合に【True】を返す
' --------------------------------------------------------------------------

    Dim result As Range
    Set result = Range(Cells(y1, x1), Cells(y2, x2)). _
                            Find(what:=num, LookAt:=xlWhole)
    
    'numが見つかったらTrueを返す
    If Not result Is Nothing Then isExistNum = True

End Function


Findメソッドの使い方や、If Not result Is Nothing Thenの記述がピンとこない方、こちらの記事がおすすめです!
www.excel-prog.com

共通部品3(解答代入処理)

解答が決まった際に呼び出される「解答数字をセルに書き込む処理」です。

【概要】

  1. プロシージャ名(Sub)
    • AnswerSet
  2. 処理内容
    • [指定のセル]に解答数字を代入(書き込む)する処理
  3. 用意する変数(Long型)
    • y, x, answer
  4. 返り値
    • なし


【イメージ】
f:id:excel-accounting:20180601235633p:plain:w450


【コード】

Sub AnswerSet(ByVal y As Long, x As Long, answer As Long)
' ------------------------------------------------------------------
' * 機能:指定のセルに解答数字を代入する
' * 引数:【セルの行番号】,【セルの列番号】,【解答数字】
' ------------------------------------------------------------------

    With Cells(y, x)
        .Value = answer
        .Font.Bold = True '太字
        .Font.ColorIndex = 3 '赤
    End With
    
End Sub

解答数字が元々のヒント数字と区別できるよう「赤太文字」にします。
f:id:excel-accounting:20180430184235p:plain:w100

スポンサーリンク


次回予告

次回からいよいよ「解法1」の実装に入っていきますよ!

f:id:excel-accounting:20180618151802p:plain:w350


最後に

ここまでお読みいただきありがとうございました。

*引き続き連載を読んでくださるはてなブロガーの方はぜひ読者になってくださいね。

*ツイッターでもブログ更新のツイートをしているので、こちらもフォローしてくれると嬉しいです。

第3回目へつづきます!
VBAでナンプレを解いてみよう③

スポンサーリンク