Hi Leute,
Ich weis, dass es bereits ein µit daraüber gab, aber das hab ich erst gesehen, als ich schon fast fertig war
Derzeit unterstüzte Lösungsmethoden:
- Jede Zahl darf in jeder Reihe nur einmal vorkommen.
- Jede Zahl darf in jeder Spalte nur einmal vorkommen.
- Jede Zahl darf in jedem Quadrat nur einmal vorkommen.
Sourcecode:
Spoiler anzeigen
#NoAutoIt3Execute
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <Misc.au3>
Opt("GuiCloseOnEsc", 0)
Opt("GuiOnEventMode", 1)
Opt("MouseCoordMode", 2)
;~ If $CmdLine[0] > 1 And StringLen($CmdLine[1]) == 81 Then _Solve($CmdLine[1])
[/autoit] [autoit][/autoit] [autoit]Global $aGuiInputs[81]
Global $aPossible[81]
Global Const $iGUISize = 500
Global Const $sEmptyChar = '0' ; nicht verändern!
Global Const $aPossibleChars[9] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
Global Const $sPossibleChars = '123456789'
Global Const $sTitle = "SUDOKU-SOLVE-ENGINE by oetzn"
Global Const $bDebug = True
Global Const $bTime = True
$hGui = GUICreate($sTitle, $iGUISize, $iGUISize)
[/autoit] [autoit][/autoit] [autoit]$Menu1 = GUICtrlCreateMenu("Sudoku")
GUICtrlCreateMenuItem("Einfügen", $Menu1)
GUICtrlSetOnEvent(-1, "_Insert")
GUICtrlCreateMenuItem("Lösen", $Menu1)
GUICtrlSetOnEvent(-1, "_Solve")
GUICtrlCreateMenuItem("Datei laden", $Menu1)
GUICtrlSetOnEvent(-1, "_LoadFile")
GUICtrlSetState(-1, $GUI_DISABLE)
GUICtrlCreateMenuItem("", $Menu1)
GUICtrlCreateMenuItem("Beenden", $Menu1)
GUICtrlSetOnEvent(-1, "_Exit")
$Menu2 = GUICtrlCreateMenu("Hilfe")
GUICtrlCreateMenuItem("Über", $Menu2)
_CreateInputs($iGUISize / 13)
[/autoit] [autoit][/autoit] [autoit]GUISetState(@SW_SHOW, $hGui)
GUISetOnEvent(-3, "_Exit", $hGui)
HotKeySet("^v", "_SudokuFromClipboard")
[/autoit] [autoit][/autoit] [autoit]While 1
Sleep(10)
WEnd
Func _CreateInputs($iSize)
Local $x, $y
Local $iXExtra, $iYExtra
Local $iCounter = 0
For $x = 1 To 9
For $y = 1 To 9
$aGuiInputs[$iCounter] = GUICtrlCreateInput("", $y * $iSize + $iYExtra, $x * $iSize + $iXExtra, $iSize, $iSize, BitAND($ES_CENTER, $ES_NUMBER))
$iCounter += 1
GUICtrlSetFont(-1, $iSize / 2)
If Mod($y, 3) = 0 Then $iYExtra += $iSize
Next
$iYExtra = 0
If Mod($x, 3) = 0 Then $iXExtra += $iSize
Next
EndFunc ;==>_CreateInputs
Func _GetContent()
If Not IsArray($aGuiInputs) Then Return
Local $sSudoku
For $x = 0 To 80
If GUICtrlRead($aGuiInputs[$x]) = '' Then
$sSudoku &= $sEmptyChar
Else
$sSudoku &= GUICtrlRead($aGuiInputs[$x])
EndIf
Next
Return $sSudoku
EndFunc ;==>_GetContent
Func _Insert()
$sRet = InputBox("Sudoku einfügen!", "Bitte geben Sie hier einen String aus 81 Zahlen ein." & @LF & "Der String wird von links nach rechts eingetragen!")
If @error Then Return
If Not _ValidateSudoku($sRet) Then
MsgBox(16, "ERROR", "Ein Fehler ist aufgetreten!" & @CRLF & "Das Sudoku ist nicht gültig!", 5)
Return
EndIf
For $x = 0 To 80
$sTempChar = StringLeft($sRet, 1)
$sRet = StringTrimLeft($sRet, 1)
If $sTempChar = $sEmptyChar Then
$aPossible[$x] = $sPossibleChars
ContinueLoop
EndIf
GUICtrlSetData($aGuiInputs[$x], '')
GUICtrlSetData($aGuiInputs[$x], $sTempChar)
$aPossible[$x] = $sTempChar
Next
If $bDebug Then AdlibRegister("_Debug", 10)
[/autoit] [autoit][/autoit] [autoit]EndFunc ;==>_Insert
[/autoit] [autoit][/autoit] [autoit]Func _Solve()
Local $sSudoku = _GetContent()
If Not _ValidateSudoku($sSudoku) Then
MsgBox(16, "ERROR", "Ein Fehler ist aufgetreten!" & @CRLF & "Das Sudoku ist nicht gültig!")
Return
EndIf
Do
[/autoit] [autoit][/autoit] [autoit]$iEmptyFields = __Solve_Method_CheckChange()
[/autoit] [autoit][/autoit] [autoit]__Solve_Method_EliminatePossibilitesInRow($sSudoku)
__Solve_Method_EliminatePossibilitesInColumn($sSudoku)
__Solve_Method_EliminatePossibilitesInSquare($sSudoku)
__Solve_Method_OnlyOneOccurenceInRow()
__Solve_Method_OnlyOneOccurenceInColumn()
__Solve_Method_OnlyOneOccurenceInSquare()
__Solve_Method_CheckForSinglePoss()
[/autoit] [autoit][/autoit] [autoit]Until $iEmptyFields == __Solve_Method_CheckChange()
[/autoit] [autoit][/autoit] [autoit]EndFunc ;==>_Solve
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]Func __Solve_Method_EliminatePossibilitesInRow($sInput)
; by oetzn (autoit.de)
If Not _ValidateSudoku($sInput) Then Return
Local $iCount
Local $iPos
Local $sTempRow
If $bTime Then $TempTimer = TimerInit()
[/autoit] [autoit][/autoit] [autoit]For $i = 1 To 81 Step 9
$sTempRow = StringMid($sInput, $i, 9)
For $j = 1 To 9
$iCount = 0
$iPos = ''
For $k = 1 To 9
If StringMid($sTempRow, $k, 1) == $j Then
$iCount += 1
$iPos = $k
EndIf
Next
If $iCount == 1 Then
For $m = 1 To 9
If $m == $iPos Then ContinueLoop
$aPossible[$i + $m - 2] = StringReplace($aPossible[$i + $m - 2], String($j), '')
Next
EndIf
Next
Next
If $bTime Then ConsoleWrite("__Solve_Method_EliminatePossibilitesInRow: " & TimerDiff($TempTimer) & " ms " & @CRLF)
[/autoit] [autoit][/autoit] [autoit]EndFunc ;==>__Solve_Method_EliminatePossibilitesInRow
[/autoit] [autoit][/autoit] [autoit]Func __Solve_Method_EliminatePossibilitesInColumn($sInput)
; by oetzn (autoit.de)
If Not _ValidateSudoku($sInput) Then Return
[/autoit] [autoit][/autoit] [autoit]Local $iPosInStr = 1
Local $sTempColumn
If $bTime Then $TempTimer = TimerInit()
[/autoit] [autoit][/autoit] [autoit]For $iOffset = 0 To 8
$sTempColumn = ''
For $i = 1 To 81 Step 9
$sTempColumn &= StringMid($sInput, $i + $iOffset, 1)
Next
For $j = 1 To 9
$iCount = 0
$iPos = ''
For $k = 1 To 9
If StringMid($sTempColumn, $k, 1) == $j Then
$iCount += 1
$iPos = $k
EndIf
Next
If $iCount == 1 Then
For $m = 1 To 9
If $m == $iPos Then ContinueLoop
$aPossible[$iPosInStr + ($m - 1) * 9 - 1] = StringReplace($aPossible[$iPosInStr + ($m - 1) * 9 - 1], String($j), '')
Next
EndIf
Next
$iPosInStr += 1
Next
If $bTime Then ConsoleWrite("__Solve_Method_EliminatePossibilitesInColumn: " & TimerDiff($TempTimer) & " ms " & @CRLF)
[/autoit] [autoit][/autoit] [autoit]EndFunc ;==>__Solve_Method_EliminatePossibilitesInColumn
[/autoit] [autoit][/autoit] [autoit]Func __Solve_Method_EliminatePossibilitesInSquare($sInput)
; by oetzn (autoit.de)
If Not _ValidateSudoku($sInput) Then Return
[/autoit] [autoit][/autoit] [autoit]Local $aParts[27]
Local $iCounter = 0
Local $sTempSquare
Local $iOffsetExt
If $bTime Then $TempTimer = TimerInit()
[/autoit] [autoit][/autoit] [autoit]For $i = 1 To 81 Step 3
$aParts[$iCounter] = StringMid($sInput, $i, 3)
$iCounter += 1
Next
For $iOffsetBig = 0 To 26 Step 9
For $iOffsetSmall = 0 To 2
$sTempSquare = ''
For $i = 0 To 8 Step 3
$sTempSquare &= $aParts[$i + $iOffsetSmall + $iOffsetBig]
Next
For $j = 1 To 9
$iCount = 0
$iPos = ''
For $k = 1 To 9
If StringMid($sTempSquare, $k, 1) == $j Then
$iCount += 1
$iPos = $k
EndIf
Next
If $iCount == 1 Then
For $m = 1 To 9
If $m == $iPos Then ContinueLoop
$iOffsetExt = 0
Select
Case $m <= 3
$iOffsetExt = 0
Case $m > 3 And $m <= 6
$iOffsetExt = 5 + $m
Case $m >= 7
$iOffsetExt = 11 + $m
EndSelect
$aPossible[$iOffsetBig * 3 + $iOffsetSmall * 3 + $iOffsetExt] = StringReplace($aPossible[$iOffsetBig * 3 + $iOffsetSmall * 3 + $iOffsetExt], String($j), '')
Next
EndIf
Next
Next
Next
If $bTime Then ConsoleWrite("__Solve_Method_EliminatePossibilitesInSquare: " & TimerDiff($TempTimer) & " ms " & @CRLF)
[/autoit] [autoit][/autoit] [autoit]EndFunc ;==>__Solve_Method_EliminatePossibilitesInSquare
[/autoit] [autoit][/autoit] [autoit]Func __Solve_Method_OnlyOneOccurenceInRow()
; by oetzn (autoit.de)
Local $iCount
Local $iPos
If $bTime Then $TempTimer = TimerInit()
[/autoit] [autoit][/autoit] [autoit]For $i = 0 To 80 Step 9
For $j = 1 To 9
$iCount = 0
$iPos = ''
For $k = $i To $i + 8
If StringInStr($aPossible[$k], String($j)) Then
$iCount += 1
$iPos = $k
EndIf
Next
If $iCount == 1 Then $aPossible[$iPos] = String($j)
Next
Next
If $bTime Then ConsoleWrite("__Solve_Method_OnlyOneOccurenceInRow: " & TimerDiff($TempTimer) & " ms " & @CRLF)
[/autoit] [autoit][/autoit] [autoit]EndFunc ;==>__Solve_Method_OnlyOneOccurenceInRow
[/autoit] [autoit][/autoit] [autoit]Func __Solve_Method_OnlyOneOccurenceInColumn()
; by oetzn (autoit.de)
Local $iCount
Local $iPos
If $bTime Then $TempTimer = TimerInit()
[/autoit] [autoit][/autoit] [autoit]For $iOffset = 0 To 8
For $j = 1 To 9
$iCount = 0
$iPos = ''
For $i = 0 To 80 Step 9
If StringInStr($aPossible[$i + $iOffset], String($j)) Then
$iCount += 1
$iPos = $i + $iOffset
EndIf
Next
If $iCount == 1 Then $aPossible[$iPos] = String($j)
Next
Next
If $bTime Then ConsoleWrite("__Solve_Method_OnlyOneOccurenceInColumn: " & TimerDiff($TempTimer) & " ms " & @CRLF)
[/autoit] [autoit][/autoit] [autoit]EndFunc ;==>__Solve_Method_OnlyOneOccurenceInColumn
[/autoit] [autoit][/autoit] [autoit]Func __Solve_Method_OnlyOneOccurenceInSquare()
; by oetzn (autoit.de)
Local $iCount
Local $iPos
If $bTime Then $TempTimer = TimerInit()
[/autoit] [autoit][/autoit] [autoit]For $iOffset1 = 0 To 54 Step 27
For $iOffset2 = 0 To 6 Step 3
For $j = 1 To 9
$iCount = 0
$iPos = ''
For $iOffset3 = 0 To 18 Step 9
For $iOffset4 = 0 To 2
If StringInStr($aPossible[$iOffset1 + $iOffset2 + $iOffset3 + $iOffset4], $j) Then
$iCount += 1
$iPos = $iOffset1 + $iOffset2 + $iOffset3 + $iOffset4
EndIf
Next
Next
If $iCount == 1 Then $aPossible[$iPos] = String($j)
Next
Next
Next
If $bTime Then ConsoleWrite("__Solve_Method_OnlyOneOccurenceInColumn: " & TimerDiff($TempTimer) & " ms " & @CRLF)
[/autoit] [autoit][/autoit] [autoit]EndFunc ;==>__Solve_Method_OnlyOneOccurenceInSquare
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]Func __Solve_Method_CheckForSinglePoss()
[/autoit] [autoit][/autoit] [autoit]If $bTime Then $TempTimer = TimerInit()
[/autoit] [autoit][/autoit] [autoit]For $i = 0 To 80
If StringLen($aPossible[$i]) == 1 Then GUICtrlSetData($aGuiInputs[$i], $aPossible[$i])
Next
If $bTime Then ConsoleWrite("__Solve_Method_CheckForSinglePoss: " & TimerDiff($TempTimer) & " ms " & @CRLF)
[/autoit] [autoit][/autoit] [autoit]EndFunc ;==>__Solve_Method_CheckForSinglePoss
[/autoit] [autoit][/autoit] [autoit]Func __Solve_Method_CheckChange()
Local $iEmptyCounter = 0
For $i = 0 To 80
If StringLen($aPossible[$i]) > 1 Then $iEmptyCounter += 1
Next
Return $iEmptyCounter
EndFunc ;==>__Solve_Method_CheckChange
Func _ValidateSudoku($sInput)
; by oetzn (autoit.de)
Local $bValid = True
If StringRegExp($sInput, '[^0-9]', 0) = 1 Then $bValid = False
If StringLen($sInput) <> 81 Then $bValid = False
If Not IsString($sInput) Then $bValid = False
Return $bValid
EndFunc ;==>_ValidateSudoku
Func _Debug()
$aInfo = GUIGetCursorInfo($hGui)
If $aInfo[4] > 0 Then
For $i = 0 To UBound($aGuiInputs, 1) - 1
If $aGuiInputs[$i] == $aInfo[4] Then ExitLoop
Next
ToolTip("Possbile Chars: " & $aPossible[$i])
Else
ToolTip("")
EndIf
EndFunc ;==>_Debug
Func _SudokuFromClipboard()
Local $sClipboard = ClipGet()
If WinGetTitle("[ACTIVE]", "") == $sTitle Then
If _ValidateSudoku($sClipboard) Then
For $x = 0 To 80
$sTempChar = StringLeft($sClipboard, 1)
$sClipboard = StringTrimLeft($sClipboard, 1)
If $sTempChar = $sEmptyChar Then
$aPossible[$x] = $sPossibleChars
ContinueLoop
EndIf
GUICtrlSetData($aGuiInputs[$x], '')
GUICtrlSetData($aGuiInputs[$x], $sTempChar)
$aPossible[$x] = $sTempChar
Next
Else
MsgBox(16, "ERROR", "Ein Fehler ist aufgetreten!" & @CRLF & "Das Sudoku ist nicht gültig!", 2)
Return
EndIf
If $bDebug Then AdlibRegister("_Debug", 10)
[/autoit] [autoit][/autoit] [autoit]Else
HotKeySet("^v")
Send("^v")
HotKeySet("^v", "_SudokuFromClipboard")
EndIf
EndFunc ;==>_SudokuFromClipboard
Func _LoadFile()
Sleep(10)
EndFunc ;==>_LoadFile
Func _Exit()
Exit
EndFunc ;==>_Exit
Aufgrund der noch spärlich Ausstattung mit Lösungswegen, kann das Skript natürlich nicht alle Sudokus lösen, aber mit einfach kommt es schon zurecht
Bedienung:
Möglichkeit 1:
Ihr tippt die Zahlen direkt in die Inputfelder ein. (Mit Tab usw)
Möglichkeit 2:
Ihr klickt auf den Menübutton 'Sudoku' und wählt 'Einfügen'.
Hier müsst ihr dann das Sudoku eingeben in folgender Form:
Von links nach rechts gelesen. Links oben beginnend. Jeder Leerstelle ist eine '0'.
Möglichkeit 3:
Ihr kopiert einen solchen Sudokustring in die Zwischenablage, setzt das Fenster in den Vordergrund und drückt 'STRG + V'
Neuerungen die noch kommen:
- Mehr Lösungswege
- Abspeichern von Sudokus ermöglichen
- Abarbeiten von einer Datei, die mehere Sudoku-Strings enthält
Viel Spaß damit
Konstruktive Kritik, Lob & Verbesserungsvorschläge sind gerne gesehen