Sudoku Rätsel lösen

Hallo,
wenn man Sudokus löst und auf einmal festhängt kann es ja hilfreich sein, die bisherigen gefundenen Zahlen anhand der Lösung zu prüfen ob denn da nicht schon ein Fehler ist und das ggfs. korigieren.
Ich habe das Makro an ca. 30 Sudokus getestet und es funktionierte perfekt, was natürlich kein Beweis ist dass es alle Sudokus lösen kann und mir ist auch sehr unklar geblieben ob es für ein Sudoku mehrere Lösungen geben könnte.
Das Makro erwartet die Sudoku Zahlen in Tabelle1 im Bereich „A1:I9“ und präsentiert die Lösung in Tabelle2 „A1:I9“.
Gruß
Reinhard

Option Explicit
Sub sudo()
Dim ws1 As Worksheet, z As Byte, s As Byte, m(9, 9) As String, n As Byte
Dim zq As Byte, sq As Byte, Zelle, Wert As String, neu As Boolean
On Error Resume Next 'wegen Fehler bei CountIf wenn nichts gefunden wird
Set ws1 = Worksheets("Tabelle1")
With Worksheets("Tabelle2")
 ws1.Range("A1:I9").Copy Destination:=.Range("A1")
 For z = 1 To 9
 For s = 1 To 9
 If .Cells(z, s) = "" Then
 m(z, s) = "123456789"
 Else
 m(z, s) = .Cells(z, s)
 End If
 Next s
 Next z
End With
nochmal:
With Worksheets("Tabelle2")
 For z = 1 To 9 'waagrechte Prüfung
 For s = 1 To 9
 If Len(.Cells(z, s)) 1 Then
 For n = 1 To 9
 If Application.WorksheetFunction.CountIf(.Range(.Cells(z, 1), .Cells(z, 9)), CStr(n)) \> 0 Then
 m(z, s) = Replace(m(z, s), CStr(n), "")
 If Len(m(z, s)) = 1 Then
 .Cells(z, s) = m(z, s)
 GoTo nochmal
 End If
 End If
 Next n
 End If
 Next s
 Next z
 For s = 1 To 9 'senkrechte Prüfung
 For z = 1 To 9
 If Len(m(z, s)) \> 1 Then
 For n = 1 To 9
 If Application.WorksheetFunction.CountIf(.Range(.Cells(1, s), .Cells(9, s)), CStr(n)) \> 0 Then
 m(z, s) = Replace(m(z, s), CStr(n), "")
 If Len(m(z, s)) = 1 Then
 .Cells(z, s) = m(z, s)
 GoTo nochmal
 End If
 End If
 Next n
 Else
 m(z, s) = .Cells(z, s)
 End If
 Next z
 Next s
 For z = 1 To 9 'quadratische Prüfung
 For s = 1 To 9
 zq = Int((z - 1) / 3) \* 3 + 1
 sq = Int((s - 1) / 3) \* 3 + 1
 If Len(m(z, s)) \> 1 Then
 For n = 1 To 9
 If Application.WorksheetFunction.CountIf(.Range(.Cells(zq, sq), .Cells(zq, sq).Offset(2, 2)), CStr(n)) \> 0 Then
 m(z, s) = Replace(m(z, s), CStr(n), "")
 If Len(m(z, s)) = 1 Then
 .Cells(z, s) = m(z, s)
 GoTo nochmal
 End If
 End If
 Next n
 End If
 Next s
 Next z
 For z = 1 To 9
 For s = 1 To 9
 .Cells(z, s) = m(z, s)
 Next s
 Next z
 For z = 1 To 9 Step 3 'quadratische Prüfung auf einmalige Ziffer
 For s = 1 To 9 Step 3
 Wert = ""
 For Each Zelle In .Range(.Cells(z, s), .Cells(z, s).Offset(2, 2))
 Wert = Wert & CStr(Zelle.Value)
 Next Zelle
 For Each Zelle In .Range(.Cells(z, s), .Cells(z, s).Offset(2, 2))
 If Len(Zelle) \> 1 Then
 For n = 1 To Len(Zelle)
 If InStr(InStr(Wert, Mid(Zelle, n, 1)) + 1, Wert, Mid(Zelle, n, 1)) = 0 Then
 Zelle.Value = Mid(Zelle, n, 1)
 m(Zelle.Row, Zelle.Column) = Zelle.Value
 neu = True
 GoTo weiter
 End If
 Next n
 End If
 Next Zelle
weiter:
 Next s
 Next z
If neu = True Then
 neu = False
 For Each Zelle In .Range("A1:I9")
 If Len(Zelle) \> 1 Then Zelle.Value = ""
 Next Zelle
 GoTo nochmal
End If
 ws1.Range("A1:I9").Copy Destination:=.Range("A11")
 .Activate
End With
End Sub

Function doppelt(ByVal Wert)
Dim n
With Worksheets("Tabelle2")
 doppelt = False
 For n = 1 To Len(Wert)
 If InStr(InStr(Wert, n) + 1, Wert, n) 0 Then
 doppelt = True
 Exit For
 End If
 Next n
End With
End Function

Hallo Reinhard
Ich bin hell begeistert von Deinem Makro!
Ich habe dazu eine Frage: Gibt es eine Mindest-Anzahl von Zahlen, die erfasst sein müssen, damit mit Deinem Makro eine eindeutige Lösung gefunden werden kann? Ich kann mir vorstellen, dass eine Antwort schwierig zu definieren ist mit neun Zeilen und Spalten und vier 3er-Quadraten.

Du schreibst

sehr unklar, ob es für ein Sudoku mehrere Lösungen geben könnte.

Dazu folgendes. Ich habe eine Tabelle1 mit den Werten:
1 2 0 0 0 6 7 0 0
0 0 6 7 0 0 0 0 3
7 0 9 0 2 3 4 0 6
0 3 0 5 6 0 8 0 1
5 0 0 0 0 0 0 0 0
0 9 1 2 0 4 0 6 7
0 0 5 0 0 8 0 0 0
6 0 8 9 0 0 3 4 0
9 1 0 3 0 5 6 0 0 0 = Leere Zelle

In Deiner Tabelle2 wird als Lösung für fehlende Zahlen 58 vorgeschlagen. Man kann die beiden Ziffern beliebig eingeben, mit beiden kommt das Sudoku zu einer Lösung. Ist das ein Hinweis darauf, dass es für ein Sudoku mehrere Lösungen geben kann? – Oder habe ich da eine Antwort auf eine Frage, die ich gar nicht richtig verstanden habe?

Viele Grüsse
Niclaus

Hallo Niclaus,

Ich habe dazu eine Frage: Gibt es eine Mindest-Anzahl von
Zahlen, die erfasst sein müssen, damit mit Deinem Makro eine
eindeutige Lösung gefunden werden kann? Ich kann mir
vorstellen, dass eine Antwort schwierig zu definieren ist mit
neun Zeilen und Spalten und vier 3er-Quadraten.

Vielleicht können die vom Mathebrett dies beantworten, ich hingegen habe da keinerlei Überblick wie man ggfs. eine Mindestanzahl an vorgegebenen Zahlen berechnet und ob diese Anzahl fest ist oder noch von der örtlichen Verteilung der Zahlen im Sudoku abhängen könnte.
Möglicherweise ist dies noch davon abhängig welche Zahlen man anfangs „verteilt“.
In einem anderen Makroansatz probierte ich, alle Zahlenmöglichkeiten aufgrund der vorgegebenen Zahlen durchzuspielen. Aber das brach ich ab, da dies viel zu lange dauerte.

Ist das ein
Hinweis darauf, dass es für ein Sudoku mehrere Lösungen geben
kann? – Oder habe ich da eine Antwort auf eine Frage, die
ich gar nicht richtig verstanden habe?

Geht mir genauso, ich weiß nix und davon viel :smile:

Gruß
Reinhard

Hallo Reinhard,

Hut ab, vor Deiner Leistung!
Ich habe auch gerade mal ein paar Sudokus ausprobiert, bei den ersten Beiden klappte es sofort, aber bei dem Dritten kam nur noch Unfug heraus… zu wenig Zahlen?

030000X97
700600Y08
000005301
108790000
000000070
520003600
050060743
002000000
070149000

Erst wenn mann z.B. für X=4 oder Y=2 einträgt klappt es wieder.

UUPS… ich sehe gerade, das ist gar kein Unfug, es sind nur bis zu 5 Möglichkeiten aufgezeigt. KLASSE!
Ist ne Menge Leistung für so ein kleines Makro!!!

Gruß Detlef

Mein lieber Scholli
Hallo Reinhard,

Hut ab. Wie lange braucht man für so etwas?
Könnte man auch einen Sudoku-Generator in
Excel erstellen?

Gruß (*) Peter

Hut ab. Wie lange braucht man für so etwas?
Könnte man auch einen Sudoku-Generator in
Excel erstellen?

Hallo Peter,
leider fehlt mir ein Grundansaz wie man da vorgehen müßte dass zeitlich binnen weniger Sekunden ein Sudoku erstellt wird.
Das nachfolgende Zitat aus http://www.wikipedia.org ist einerseits Abschreckung aber auch Herausforderung.

„Der Neuseeländer Wayne Gould lernte Sudoku auf einer Japanreise kennen und brauchte sechs Jahre, um eine Software zu entwickeln, die neue Sudokus per Knopfdruck entwickeln kann.“

Gruß
Reinhard

Hallo,
wenn man Sudokus löst und auf einmal festhängt kann es ja
hilfreich sein, die bisherigen gefundenen Zahlen anhand der
Lösung zu prüfen ob denn da nicht schon ein Fehler ist und das
ggfs. korigieren.

Grüezi Reinhard
Ich habe mit Deinem sudoku-Makro weitergearbeitet und folgendes gemacht.
In der Tabelle2 habe ich in den Feldern a10 : i10 jeweils die Spaltensummen berechnet; in a10 also summe(a1:a9), analog in b10 usw. Aehnlich die Zeilensummen in den Feldern j1:j9. In j1 also summe(a1:i1) usw.
In j10 habe ich folgenden Vergleich eingegeben:
=UND( (A10*B10*C10*D10*E10* F10*G10*H10*I10)^(1/9)= 45 ;
(J1*J2*J3*J4*J5*J6*J7*J8*J9)^(1/9)=45)
Das Ergebnis WAHR oder FALSCH ist für mich die einfachste Kontrolle, ob das Sudoku wirklich stimmt.
Schliesslich habe ich ein Makro sudo_2 gebastelt.

Sub sudo_2()
With Worksheets(„Tabelle2“)
.Activate
kontrolle = .Range(„j10“)
'MsgBox kontrolle
If kontrolle = „Wahr“ Then Exit Sub

For z = 1 To 9 'ex Reinhards waagrechte Prüfung
For s = 1 To 9
If Len(.Cells(z, s)) 1 Then
ww = .Cells(z, s)
’ MsgBox "ZS " & z & s & " " & ww
GoTo weiter1
End If
wieder:
Next s
Next z

weiter1:
For n = 1 To Len(ww)
mii = Mid(ww, n, 1)
Worksheets(„Tabelle1“).Cells(z, s) = mii
’ MsgBox mii
sudo 'Reinhards Makro
Worksheets(„Tabelle1“).Cells(z, s) = „“
kontrolle = .Range(„j10“)
If kontrolle = „Wahr“ Then Exit Sub
Next n
GoTo wieder
End With

End Sub

Ich habe einige msgbox eingeschoben, damit ich für mich den Ablauf kontrollieren kann.
Dieses sudo_2() ist dann anzuwenden, wenn nach Deinem glänzenden sudo() das Ergebnis nicht eindeutig ist. Es ruft Dein sudo() auf, um jeweils die Berechnungen neu durchzuführen.
Das sudo_2 war nur dank Deiner Ideen möglich und ist stümperhaft geschrieben (Du wirst es sicher perfektionieren), aber ich hoffe, dass es bei Dir genau so gut funktioniert wie bei mir.
Grüsse
Niclaus