ExcelマクロVBAサンプル集 | ナンバーリンク(パズル)を解くVBAに挑戦3 | Excelマクロの実用サンプル、エクセルVBA集と解説



最終更新日:2014-05-22

ナンバーリンク(パズル)を解くVBAに挑戦3


では、そもそもどこが無駄なのでしょうか・・・

無駄な動きを見つけて、ひとつずつ潰していきます。



このような動きは、完全に無駄です。


余分に空白を潰してしまえば、他の数値の動きを邪魔するだけで、何も意味を成しません。

この場合は、来た方向に戻る事はありえなく、



または、



のどちらかになります。

このロジックを組み込みます。

chkAdvance

次の進む先の候補が、進んでよいかどうかを判断します。


では、これを組み込んだコードです。

Option Explicit

Private SuAry(1 To 10, 1 To 10) As String

Sub main()
  Dim iR As Integer
  Dim iC As Integer
  
  For iR = 1 To 10
    For iC = 1 To 10
      With Cells(iR + 1, iC + 1)
        If .Value = "" Or Not IsNumeric(.Value) Then
          .Value = ""
          .Font.Size = 9
          .Font.Bold = False
          .NumberFormat = "@"
          SuAry(iR, iC) = ""
        Else
          SuAry(iR, iC) = .Value
        End If
      End With
    Next
  Next
  
  iR = 1
  iC = 0
  Call getStart(iR, iC)
  Do
    If getAdvance(iR, iC, iR, iC, 0) = "完了" Then
      Exit Do
    End If
  Loop
  Range("B2:K11").Value = SuAry
End Sub

Private Function getAdvance(ByVal iR As Integer, ByVal iC As Integer, _
              ByVal iR2 As Integer, ByVal iC2 As Integer, _
              ByVal tryCnt As Integer) As String
  Dim iR3 As Integer
  Dim iC3 As Integer
  Dim iR4 As Integer
  Dim iC4 As Integer
  Dim i As Integer
  Dim rtn As String
  
  Call getEnd(iR4, iC4, SuAry(iR, iC))
  Select Case True
    Case iR4 = iR2 - 1 And iC4 = iC2, _
       iR4 = iR2 And iC4 = iC2 + 1, _
       iR4 = iR2 + 1 And iC4 = iC2, _
       iR4 = iR2 And iC4 = iC2 - 1
      Call dispCell(True)
      tryCnt = 0
      If getStart(iR, iC) = False Then
        getAdvance = "完了"
        Exit Function
      End If
      rtn = getAdvance(iR, iC, iR, iC, tryCnt)
      Select Case rtn
        Case "完了"
          getAdvance = "完了"
          Exit Function
        Case "終点"
          getAdvance = "終点"
          tryCnt = 0
          If getStart(iR, iC) = False Then
            getAdvance = "完了"
            Exit Function
          End If
        Case "破綻"
          getAdvance = "破綻"
          Exit Function
      End Select
  End Select
    
  For i = 1 To 4
    Select Case True
      Case iR4 > iR2 And iC4 > iC2
        Select Case i
          Case 1
            iR3 = iR2 + 1
            iC3 = iC2
          Case 2
            iR3 = iR2
            iC3 = iC2 + 1
          Case 3
            iR3 = iR2 - 1
            iC3 = iC2
          Case 4
            iR3 = iR2
            iC3 = iC2 - 1
        End Select
      Case iR4 > iR2 And iC4 <= iC2
        Select Case i
          Case 1
            iR3 = iR2 + 1
            iC3 = iC2
          Case 2
            iR3 = iR2
            iC3 = iC2 - 1
          Case 3
            iR3 = iR2
            iC3 = iC2 + 1
          Case 4
            iR3 = iR2 - 1
            iC3 = iC2
        End Select
      Case iR4 < iR2 And iC4 > iC2
        Select Case i
          Case 1
            iR3 = iR2 - 1
            iC3 = iC2
          Case 2
            iR3 = iR2
            iC3 = iC2 + 1
          Case 3
            iR3 = iR2 + 1
            iC3 = iC2
          Case 4
            iR3 = iR2
            iC3 = iC2 - 1
        End Select
      Case iR4 = iR2 And iC4 > iC2
        Select Case i
          Case 1
            iR3 = iR2
            iC3 = iC2 + 1
          Case 2
            iR3 = iR2
            iC3 = iC2 - 1
          Case 3
            iR3 = iR2 - 1
            iC3 = iC2
          Case 4
            iR3 = iR2 + 1
            iC3 = iC2
        End Select
      Case iR4 < iR2 And iC4 <= iC2
        Select Case i
          Case 1
            iR3 = iR2 - 1
            iC3 = iC2
          Case 2
            iR3 = iR2
            iC3 = iC2 - 1
          Case 3
            iR3 = iR2 + 1
            iC3 = iC2
          Case 4
            iR3 = iR2
            iC3 = iC2 + 1
        End Select
      Case iR4 = iR2 And iC4 <= iC2
        Select Case i
          Case 1
            iR3 = iR2
            iC3 = iC2 - 1
          Case 2
            iR3 = iR2
            iC3 = iC2 + 1
          Case 3
            iR3 = iR2 - 1
            iC3 = iC2
          Case 4
            iR3 = iR2 + 1
            iC3 = iC2
        End Select
    End Select
    
    If iC3 >= 1 And iC3 <= 10 And iR3 >= 1 And iR3 <= 10 Then
      If chkAdvance(iR3, iC3, SuAry(iR, iC)) = True Then
        If SuAry(iR3, iC3) = "" Then
          tryCnt = tryCnt + 1
          Call dispCell(True, iR3, iC3, SuAry(iR, iC) & "-" & tryCnt)
          rtn = getAdvance(iR, iC, iR3, iC3, tryCnt)
          Select Case rtn
            Case "完了"
              getAdvance = "完了"
              Exit Function
          End Select
          If Not IsNumeric(SuAry(iR3, iC3)) Then
            tryCnt = tryCnt - 1
            Call dispCell(True, iR3, iC3, "")
          End If
        End If
      End If
    End If
  Next
  If IsNumeric(SuAry(iR2, iC2)) Then
    getAdvance = "破綻"
  Else
    tryCnt = tryCnt - 1
    Call dispCell(True, iR2, iC2, "")
    getAdvance = "別ルート探索"
  End If
End Function

Private Function chkAdvance(ByVal iR As Integer, ByVal iC As Integer, ByVal i As Integer) As Boolean
  Dim cnt As Integer
  cnt = 0
  If iR <> 1 And iC <> 1 Then
    If InStr(SuAry(iR - 1, iC - 1), i & "-") > 0 Or SuAry(iR - 1, iC - 1) = CStr(i) Then
      cnt = cnt + 1
    End If
    If InStr(SuAry(iR - 1, iC), i & "-") > 0 Or SuAry(iR - 1, iC) = CStr(i) Then
      cnt = cnt + 1
    End If
    If InStr(SuAry(iR, iC - 1), i & "-") > 0 Or SuAry(iR, iC - 1) = CStr(i) Then
      cnt = cnt + 1
    End If
    If cnt >= 3 Then
      chkAdvance = False
      Exit Function
    End If
  End If
  
  cnt = 0
  If iR <> 10 And iC <> 1 Then
    If InStr(SuAry(iR + 1, iC - 1), i & "-") > 0 Or SuAry(iR + 1, iC - 1) = CStr(i) Then
      cnt = cnt + 1
    End If
    If InStr(SuAry(iR + 1, iC), i & "-") > 0 Or SuAry(iR + 1, iC) = CStr(i) Then
      cnt = cnt + 1
    End If
    If InStr(SuAry(iR, iC - 1), i & "-") > 0 Or SuAry(iR, iC - 1) = CStr(i) Then
      cnt = cnt + 1
    End If
    If cnt >= 3 Then
      chkAdvance = False
      Exit Function
    End If
  End If
  
  cnt = 0
  If iR <> 1 And iC <> 10 Then
    If InStr(SuAry(iR - 1, iC + 1), i & "-") > 0 Or SuAry(iR - 1, iC + 1) = CStr(i) Then
      cnt = cnt + 1
    End If
    If InStr(SuAry(iR - 1, iC), i & "-") > 0 Or SuAry(iR - 1, iC) = CStr(i) Then
      cnt = cnt + 1
    End If
    If InStr(SuAry(iR, iC + 1), i & "-") > 0 Or SuAry(iR, iC + 1) = CStr(i) Then
      cnt = cnt + 1
    End If
    If cnt >= 3 Then
      chkAdvance = False
      Exit Function
    End If
  End If
  
  cnt = 0
  If iR <> 10 And iC <> 10 Then
    If InStr(SuAry(iR + 1, iC + 1), i & "-") > 0 Or SuAry(iR + 1, iC + 1) = CStr(i) Then
      cnt = cnt + 1
    End If
    If InStr(SuAry(iR + 1, iC), i & "-") > 0 Or SuAry(iR + 1, iC) = CStr(i) Then
      cnt = cnt + 1
    End If
    If InStr(SuAry(iR, iC + 1), i & "-") > 0 Or SuAry(iR, iC + 1) = CStr(i) Then
      cnt = cnt + 1
    End If
    If cnt >= 3 Then
      chkAdvance = False
      Exit Function
    End If
  End If
  chkAdvance = True
End Function

Private Sub dispCell(ByVal blnDisp As Boolean, _
           Optional ByVal iR As Integer = 0, Optional ByVal iC As Integer = 0, _
           Optional ByVal dispStr As String = "")
  If iR = 1 And iC = 9 And dispStr = "1-1" Then
    DoEvents
  End If
  If iR <> 0 And iC <> 0 Then
    SuAry(iR, iC) = dispStr
  End If
  If blnDisp = True Then
    Range("B2:K11").Value = SuAry
    DoEvents
  End If
End Sub

Private Function getStart(ByRef iR As Integer, ByRef iC As Integer) As Boolean
  iC = iC + 1
  If RowColAjust(iR, iC) = False Then
    getStart = False
    Exit Function
  End If
  
  Do
    If IsNumeric(SuAry(iR, iC)) Then
      If chkEnd(iR, iC) <> True Then
        getStart = True
        Exit Function
      End If
    End If
    iC = iC + 1
    If RowColAjust(iR, iC) = False Then
      getStart = False
      Exit Function
    End If
  Loop
End Function

Private Function RowColAjust(ByRef iR As Integer, ByRef iC As Integer) As Boolean
  If iC > 10 Then
    iR = iR + 1
    iC = 1
  End If
  If iR > 10 Then
    RowColAjust = False
    Exit Function
  End If
  RowColAjust = True
End Function

Private Function chkEnd(ByVal iR As Integer, ByVal iC As Integer) As Boolean
  Dim iR2 As Integer
  Dim iC2 As Integer

  Call getEnd(iR2, iC2, SuAry(iR, iC))

  If iR2 = iR And iC2 = iC Then
    chkEnd = True
  Else
    chkEnd = False
  End If
End Function

Private Sub getEnd(ByRef iR2 As Integer, ByRef iC2 As Integer, ByVal i As String)
  iR2 = 10
  iC2 = 10
  Do
    If SuAry(iR2, iC2) = i Then
      Exit Sub
    End If
    iC2 = iC2 - 1
    If iC2 < 1 Then
      iR2 = iR2 - 1
      iC2 = 10
    End If
    If iR2 < 1 Then
      Exit Sub
    End If
  Loop
End Sub


だいぶ、それらしい動きになってきました。

それでも、まだ正解にたどり着ける気がしません。

まだまだ、無駄が多いということですね。

4へ続きます。


ナンバーリンク(パズル)を解くVBAに挑戦 : 1 2 3 4 5 6 7 8




同じテーマ「ExcelマクロVBAサンプル集」の記事

ナンバーリンクを解くVBAのパフォーマンス改善3
アメブロの記事本文をVBAでバックアップする6
数独(ナンプレ)を解くVBAに挑戦5
数独(ナンプレ)を解くアルゴリズムの要点とパフォーマンスの検証4

新着記事 ・・・新着記事一覧を見る

SUMIFの間違いによるパフォーマンスの低下について|エクセル関数超技(6月17日)
条件式のいろいろな書き方:TrueとFalseの判定とは|ExcelマクロVBA技術解説(6月15日)
空白セルを正しく判定する方法2|ExcelマクロVBA技術解説(5月6日)
フルパスをディレクトリ、ファイル名、拡張子に分ける|ExcelマクロVBA技術解説(4月15日)
テキストボックスの各種イベント|Excelユーザーフォーム入門(4月9日)
フォルダ(サブフォルダも全て)削除する、Optionでファイルのみ削除|ExcelマクロVBAサンプル集(4月4日)
最後の空白(や指定文字)以降の文字を取り出す|エクセル関数超技(3月26日)
先頭の数値、最後の数値を取り出す|エクセル関数超技(3月26日)
Excelファイルを開かずにシート名をチェック|ExcelマクロVBAサンプル集(3月23日)
数式の参照しているセルを取得する|ExcelマクロVBAサンプル集(3月18日)

アクセスランキング ・・・ ランキング一覧を見る

1.最終行の取得(End,Rows.Count)|ExcelマクロVBA入門
2.RangeとCellsの使い方|ExcelマクロVBA入門
3.徹底解説(VLOOKUP,MATCH,INDEX,OFFSET)|エクセル関数超技
4.Range以外の指定方法(Cells,Rows,Columns)|ExcelマクロVBA入門
5.変数とデータ型(Dim)|ExcelマクロVBA入門
6.セルのコピー&値の貼り付け(PasteSpecial)|ExcelマクロVBA入門
7.セルの参照範囲を可変にする(OFFSET,COUNTA,MATCH)|エクセル関数超技
8.ひらがな⇔カタカナの変換|エクセル基本操作
9.定数と型宣言文字(Const)|ExcelマクロVBA入門
10.CSVの読み込み方法|ExcelマクロVBAサンプル集



  • >
  • >
  • >
  • ナンバーリンク(パズル)を解くVBAに挑戦3

  • このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。


    記述には細心の注意をしたつもりですが、
    間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
    なお、掲載のVBAコードは自己責任で使ってください。万一データ破損等の損害が発生しても責任は負いません。

    ↑ PAGE TOP