数独(再挑戦)⑥ 一つしかないなら、それで確定(の続き)

昨日は、行内に一つしかない数字があったならば、その数字でセルを確定させることに挑戦した。
infoment.hatenablog.com

昨日は「行」を作成したところで時間切れ。今日は残りに挑戦する。
f:id:Infoment:20191206222211p:plain

単純に1行ないし1列抜き出して調べるのは、あまり難しくない。しかし3×3や9×9,27×27などとなれば、途端にややこしくなる。

今回はこのために、二つの関数を新たに作成した。

  1. 配列の中で、Resizeっぽくその一部を抽出
  2. 配列の中で、指定値を探してその行列番号を返す
Private Sub UniqueExistence()
    Dim r As Long, r2 As Long
    Dim c As Long, c2 As Long
    Dim arr As Variant
    Dim i As Long
        For r = 1 To 27
            ' 1行スライスして、新たな配列を作成する。
            arr = WorksheetFunction.Index(TempArray, r, 0)
            ' この配列に1~9の値が幾つ含まれるか確認する。
            For i = 1 To 9
                ' 調査した値が一つしかない場合、確定可能。
                If ArrayCountIF(arr, i) = 1 Then
                    ' 一つしかなかった値の列番号を取得。
                    ' ※完全一致で取得しない場合、正しい結果にならない。要注意。
                    c = WorksheetFunction.Match(i, arr, 0)
                    ' 27×27の行列を、9×9に換算する。
                    r2 = WorksheetFunction.RoundUp(r / 3, 0)
                    c2 = WorksheetFunction.RoundUp(c / 3, 0)
                    ' 上記で求めたセルの値が未確定の場合、確定させる。
                    If FixedNumber(r2, c2) = 0 Then
                        FixedCell r2, c2, i
                    End If
                End If
            Next
        Next
        
        ' -----------------------↓↓本日追加↓↓-------------------------
        
        For c = 1 To 27
            ' 1行スライスして、新たな配列を作成する。
            arr = WorksheetFunction.Index(TempArray, 0, c)
            ' この配列に1~9の値が幾つ含まれるか確認する。
            For i = 1 To 9
                ' 調査した値が一つしかない場合、確定可能。
                If ArrayCountIF(arr, i) = 1 Then
                    ' 一つしかなかった値の列番号を取得。
                    ' ※完全一致で取得しない場合、正しい結果にならない。要注意。
                    r = WorksheetFunction.Match(i, arr, 0)
                    ' 27×27の行列を、9×9に換算する。
                    r2 = WorksheetFunction.RoundUp(r / 3, 0)
                    c2 = WorksheetFunction.RoundUp(c / 3, 0)
                    ' 上記で求めたセルの値が未確定の場合、確定させる。
                    If FixedNumber(r2, c2) = 0 Then
                        FixedCell r2, c2, i
                    End If
                End If
            Next
        Next
        
        ' 27×27のうち、9等分した9×9の範囲について、一つしか存在しない
        ' 数を探す。もしあれば、その数でセルを確定させる。
        For r = 1 To 19 Step 9
            For c = 1 To 19 Step 9
                ' 配列をリサイズして、9×9の範囲を取得。
                arr = ResizeArray(TempArray, r, c, 9, 9)
                For i = 1 To 9
                    If ArrayCountIF(arr, i) = 1 Then
                        r2 = FindInArray(arr, i)(0) + r - 1
                        c2 = FindInArray(arr, i)(1) + c - 1
                        ' 9×9の行列番号に換算する。
                        r2 = WorksheetFunction.RoundUp(r2 / 3, 0)
                        c2 = WorksheetFunction.RoundUp(c2 / 3, 0)
                        FixedCell r2, c2, i
                    End If
                Next
            Next
        Next
End Sub

' 元の配列から、指定位置を起点として、指定行数×指定列数を抜き出す。
Private Function ResizeArray(source_array As Variant, _
                             start_r_index As Long, _
                             start_c_index As Long, _
                             array_height As Long, _
                             array_width As Long) As Variant
    Dim arr() As Variant
    ReDim arr(1 To array_height, 1 To array_width)
    Dim r As Long
    Dim c As Long
        For r = 1 To array_height
            For c = 1 To array_width
                arr(r, c) = source_array(start_r_index + r - 1, _
                                         start_c_index + c - 1)
            Next
        Next
    
        ResizeArray = arr
End Function

' 指定配列内で指定値を探し、最初に見つけた値の行番号と列番号を返す。
Private Function FindInArray(source_array As Variant, _
                             faWhat As Long) As Variant
    Dim r As Long
    Dim c As Long
        For r = LBound(source_array, 1) To UBound(source_array, 1)
            For c = LBound(source_array, 2) To UBound(source_array, 2)
                If source_array(r, c) = faWhat Then
                    FindInArray = Array(r, c)
                    Exit For
                End If
            Next
        Next
End Function

結果、新たに3つのセル(黄色)で数値が確定した。
f:id:Infoment:20191206222704p:plain

思ったより増えなかったな。
明日に続きます。

参考まで。