1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Excel VBAAdvent Calendar 2017

Day 23

Excelで数独を解く

Last updated at Posted at 2017-12-16

はじめに

 『Excelで関数型プログラミングに目覚めたのかもしれない』の投稿練習用の記事です。Excelで数独を解く為に作ったツールです。簡単にするために半手動です。バックトラッキング部分のロジックはありません。

関数型プログラミングといいながら、らしくないコードですが、分かりやすさ優先です。 時間があったので、より関数型プログラミングらしく書き直しました。

用意した関数

Function DI(R, I, Optional J = 1, Optional S = "")         '
    On Error Resume Next
    If I > 0 Then S = WorksheetFunction.Index(R, I, J)
    DI = S
End Function

' MM,NN ... テーブルで定義された関数の位置情報。

Function MM(R)                          ' TABLE ROW
    MM = Application.ThisCell.Row - R.Row + 1
End Function

Function NN(R)                          ' TABLE COLUMN
    NN = Application.ThisCell.Column - R.Column + 1
End Function

' CC は CONCAT互換関数です。

Function CC(ParamArray AA())
    On Error Resume Next
    Dim S: S = ""
    Dim I: For I = 0 To UBound(AA)
        S = S & AA(I)
    Next I
    CC = S
End Function

' 追加
Function IFC(C, V, Optional S = "")
    If C Then IFC = V Else IFC = S
End Function

Function RR(R, Optional M = 1, Optional N = 1, Optional H = 0, Optional W = 1, Optional S = "")  ' RANGE RESIZE
    On Error Resume Next
    H = IFC(H = 0, R.Rows.Count - M + 1, H)
    S = R.Offset(M - 1, N - 1).Resize(H, W)
    
    RR = S
End Function

数独を解く為の関数

Function BB(S1, Optional S = "")
    Dim I: For I = 1 To 9
        If InStr(S1, I) = 0 Then S = CC(S, I)
    Next I
    BB = S
End Function

Function BC(M)
    BC = Int((M - 1) / 3) * 3 + 1
End Function

' 追加
Function BD(R, Optional C = "", Optional S = "")   ' Rの範囲の文字列をCC
   For Each C In R
      S = CC(S, C)
   Next C
   BD = S
End Function

Function NUKU(S1, S2, Optional S3 = "")            ' S1からS2を1回抜く
    NUKU = Replace(S1, S2, S3, 1, 1)
End Function

' 追加した関数を使って書き直し
'
Function AA(R1, R2, Optional S = "")
    Dim M: M = MM(R2)
    Dim N: N = NN(R2)
    Dim K: K = DI(R1, M, N)
    
    If K = 0 Then
        S = BB(CC(BD(RR(R1, M, 1, 1, 9)), BD(RR(R1, 1, N, 9, 1)), BD(RR(R1, BC(M), BC(N), 3, 3))))
    ElseIf K < 10 Then
        S = K
    End If
    AA = S
End Function

Function AB(R1, R2, R3, Optional S = "")
    Dim M: M = MM(R3)
    Dim N: N = NN(R3)

    If DI(R1, M, N) = "" Then
       Dim K: K = DI(R2, M, N)
       
       If K < 10 Then
          S = K
       Else
          S = BB(NUKU(BD(RR(R2, BC(M), BC(N), 3, 3)), K))
      
          If S = "" Then S = BB(NUKU(BD(RR(R2, M, 1, 1, 9)), K))
          If S = "" Then S = BB(NUKU(BD(RR(R2, 1, N, 9, 1)), K))
       End If
    End If
    
    AB = S

End Function


使用方法

Excelシート上に 9x9のテーブルを3つ並べて用意します。
それぞれ左から、T1_,T2_,T3_と名前をつけます。
T1_は、入力用で、初期状態では、数独の問題を埋めていきます。
T2_は、関数 =AA(T1_,T2_) で全セルを埋めます。
T3_は、関数 =AB(T1_,T2_,T3_) で全セルを埋めます。
テーブルT3_には、一意に決まった数が表示されるので、それを
テーブルT1_に手動で転記します。簡単な問題だとそのまま解けてしまいますが、
難しい問題だと、途中で一意に決まる数字が表示されなくなります。
この場合、将棋の継盤のようにテーブル3つをコピーして手動バックトラック
を行って下さい。
テーブルT2_で、数字が2桁ある場所を見つけて、テーブルT1_にどちらかを転記し、
T3_からT1_への転記を続けます。超難問でも複数の継盤を用意すれば解けるようです。

問題をT1_に入力するとこんな感じになります。

数独.png

ではでは。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?