Sudoku Solver

  • Hey,
    Ich habe grade einen Sudoku Löser geschrieben, der meiner Meinung nach ziemlich schnell für AutoIt ist. :)
    Sagt mir bitte wie ihn ihn findet. Um das Programm zu benutzen schreibt man die Sudokus in ein Text Dokument und wählt sie im Programm aus.
    Ich habe ein paar sudokus zum testen beigelegt.

    Spoiler anzeigen
    [autoit]

    ;Coded by FireAlex

    [/autoit] [autoit][/autoit] [autoit]

    Opt("MustDeclareVars",1)
    Global $aSudoku[9][9],$aSolved[9][9],$aPencilmarks[9][9][9],$iSolvedValues,$sSaves=""

    [/autoit] [autoit][/autoit] [autoit]

    Main()
    Func Main()
    Local $sTimer
    ;~ Local $sFilePath="SuperHard.txt"
    Local $sFilePath=FileOpenDialog("Choose Sudoku File",@ScriptDir,"Sudokus (*.txt)")

    [/autoit] [autoit][/autoit] [autoit]

    $aSudoku=ReadSudoku($sFilePath)

    ConsoleWrite("Solving sudoku:"&@LF&@LF)
    PrintSudoku($aSudoku)

    $sTimer=TimerInit()
    $aSudoku=SolveSudoku($aSudoku)
    ConsoleWrite(@LF&"Solved in "&TimerDiff($sTimer)&" ms"&@LF&@LF)

    PrintSudoku($aSudoku)
    SaveSudoku(StringReplace($sFilePath,".txt","_solved.txt"),$aSudoku)
    EndFunc
    Func SolveSudoku($aSudoku)
    Local $iSolvedValuesOld
    $iSolvedValues=0
    For $i=0 To 8
    For $j=0 To 8
    $aSolved[$i][$j]=0
    For $k=0 To 8
    $aPencilmarks[$i][$j][$k]=1
    Next
    Next
    Next
    For $i=0 To 8
    For $j=0 To 8
    $k=$aSudoku[$i][$j]
    If $k<>"" Then
    NewValueFound($i,$j,$k)
    EndIf
    Next
    Next

    While 1
    $iSolvedValuesOld=$iSolvedValues
    Method1()
    Method2()
    Method3()
    Method4()
    If CheckBroken() Then
    Undo()
    ContinueLoop
    EndIf
    If $iSolvedValuesOld=$iSolvedValues Then
    Guess()
    ContinueLoop
    EndIf
    If $iSolvedValues=81 Then Return $aSolved
    WEnd
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func Method1()
    Local $iSum,$iSingleCandidate
    ;http://www.sudokuoftheday.com/pages/techniques-2.php
    For $i=0 To 8
    For $j=0 To 8
    If $aSolved[$i][$j]=0 Then
    $iSum=0
    $iSingleCandidate=0
    For $k=0 To 8
    If $aPencilmarks[$i][$j][$k] Then
    $iSum+=1
    $iSingleCandidate=$k
    EndIf
    Next
    If $iSum=1 Then
    ;~ ConsoleWrite("Method 1: "&$i&" - "&$j&" - "&($iSingleCandidate+1)&@LF)
    NewValueFound($i,$j,$iSingleCandidate+1)
    EndIf
    EndIf
    Next
    Next
    EndFunc
    Func Method2()
    Local $iSum,$iSingleCell
    ;http://www.sudokuoftheday.com/pages/techniques-1.php
    ;Rows
    For $i=0 To 8;Row
    For $j=0 To 8;Number to Check
    $iSum=0
    $iSingleCell=0
    For $k=0 To 8
    If $aPencilmarks[$i][$k][$j] Then
    $iSum+=1
    $iSingleCell=$k
    EndIf
    Next
    If $iSum=1 And $aSolved[$i][$iSingleCell]=0 Then
    ;~ ConsoleWrite("Method 2: "&$i&" - "&$iSingleCell&" - "&($j+1)&@LF)
    NewValueFound($i,$iSingleCell,$j+1)
    EndIf
    Next
    Next
    EndFunc
    Func Method3()
    Local $iSum,$iSingleCell
    ;http://www.sudokuoftheday.com/pages/techniques-1.php
    ;Coloumns
    For $i=0 To 8;Coloumn
    For $j=0 To 8;Number to Check
    $iSum=0
    $iSingleCell=0
    For $k=0 To 8
    If $aPencilmarks[$k][$i][$j] Then
    $iSum+=1
    $iSingleCell=$k
    EndIf
    Next
    If $iSum=1 And $aSolved[$iSingleCell][$i]=0 Then
    ;~ ConsoleWrite("Method 3: "&$iSingleCell&" - "&$i&" - "&($j+1)&@LF)
    NewValueFound($iSingleCell,$i,$j+1)
    EndIf
    Next
    Next
    EndFunc
    Func Method4()
    Local $iSum,$iSingleCellRow,$iSingleCellColoumn
    ;http://www.sudokuoftheday.com/pages/techniques-1.php
    ;Squares
    For $i=0 To 2;Square Row
    For $j=0 To 2;Square Coloumn
    For $k=0 To 8;Number to Check
    $iSum=0
    $iSingleCellRow=0
    $iSingleCellColoumn=0
    For $l=0 To 2;Cell Row
    For $m=0 To 2;Cell Coloumn
    If $aPencilmarks[$i*3+$l][$j*3+$m][$k] Then
    $iSum+=1
    $iSingleCellRow=$i*3+$l
    $iSingleCellColoumn=$j*3+$m
    EndIf
    Next
    Next
    If $iSum=1 And $aSolved[$iSingleCellRow][$iSingleCellColoumn]=0 Then
    ;~ ConsoleWrite("Method 4: "&$iSingleCellRow&" - "&$iSingleCellColoumn&" - "&($k+1)&@LF)
    NewValueFound($iSingleCellRow,$iSingleCellColoumn,$k+1)
    EndIf
    Next
    Next
    Next
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func NewValueFound($row,$col,$value)
    ;~ ConsoleWrite("NewValueFound: "&$row&"/"&$col&" = "&$value&@LF)
    $iSolvedValues+=1
    $aSolved[$row][$col]=$value
    $value-=1
    For $i=0 To 8
    If $i=$value Then
    $aPencilmarks[$row][$col][$i]=1
    Else
    $aPencilmarks[$row][$col][$i]=0
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    If $i<>$col Then $aPencilmarks[$row][$i][$value]=0
    If $i<>$row Then $aPencilmarks[$i][$col][$value]=0
    Next

    [/autoit] [autoit][/autoit] [autoit]

    For $i=0 To 2
    For $j=0 To 2
    If Floor($row/3)*3+$i<>$row Or Floor($col/3)*3+$j<>$col Then $aPencilmarks[Floor($row/3)*3+$i][Floor($col/3)*3+$j][$value]=0
    Next
    Next

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func Guess()
    ;~ ConsoleWrite("Guessing..."&@LF)
    $sSaves=PencilmarksToString($aPencilmarks)&","&$sSaves
    For $i=0 To 8
    For $j=0 To 8
    If $aSolved[$i][$j]=0 Then
    For $k=8 To 0 Step -1
    If $aPencilmarks[$i][$j][$k]=1 Then
    NewValueFound($i,$j,$k+1)
    Return
    EndIf
    Next
    EndIf
    Next
    Next
    EndFunc
    Func Undo()
    Local $iPos
    ;~ Do

    [/autoit] [autoit][/autoit] [autoit]

    ;~ ConsoleWrite("Whoops wrong guess!..."&@LF)
    $iPos=StringInStr($sSaves,",")
    $aPencilmarks=PencilmarksFromString(StringLeft($sSaves,$iPos-1))
    $sSaves=StringMid($sSaves,$iPos+1)
    $iSolvedValues=0
    For $i=0 To 8
    For $j=0 To 8
    $aSolved[$i][$j]=0
    Next
    Next
    Method1()
    For $i=0 To 8
    For $j=0 To 8
    If $aSolved[$i][$j]=0 Then
    For $k=8 To 0 Step -1
    If $aPencilmarks[$i][$j][$k]=1 Then
    $aPencilmarks[$i][$j][$k]=0
    Return
    EndIf
    Next
    EndIf
    Next
    Next

    ;~ Until Not CheckBroken()
    EndFunc
    Func CheckBroken()
    Local $iSum
    For $i=0 To 8
    For $j=0 To 8
    $iSum=0
    For $k=0 To 8
    $iSum+=$aPencilmarks[$i][$j][$k]
    Next
    If $iSum=0 Then Return True
    Next
    Next
    Return False
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func PencilmarksToString($aPencilmarks)
    Local $sString=""
    For $i=0 To 8
    For $j=0 To 8
    For $k=0 To 8
    If $aPencilmarks[$i][$j][$k] Then $sString&=$k
    Next
    $sString&="|"
    Next
    Next
    Return $sString
    EndFunc
    Func PencilmarksFromString($sString)
    Local $aPencilmarks[9][9][9]
    Local $iPos
    For $i=0 To 8
    For $j=0 To 8
    For $k=0 To 8
    $aPencilmarks[$i][$j][$k]=0
    Next

    $iPos=StringInStr($sString,"|")
    For $k=1 To $iPos-1
    $aPencilmarks[$i][$j][0+StringMid($sString,$k,1)]=1
    Next
    $sString=StringMid($sString,$iPos+1)
    Next
    Next
    Return $aPencilmarks
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _DebugPencilmarks($aPencilmarks)
    For $i=0 To 8
    ConsoleWrite("|")
    For $j=0 To 8
    For $k=0 To 8
    If $aPencilmarks[$i][$j][$k]=1 Then
    ConsoleWrite($k+1)
    Else
    ConsoleWrite(" ")
    EndIf
    Next
    ConsoleWrite("|")
    Next
    ConsoleWrite(@LF)
    Next
    ConsoleWrite(@LF)
    ConsoleWrite(@LF)
    EndFunc
    Func PrintSudoku($aSudoku)
    For $i=0 To 8
    If Mod($i,3)=0 Then ConsoleWrite("-------------"&@LF)
    For $j =0 To 8
    If Mod($j,3)=0 Then ConsoleWrite("|")
    If $aSudoku[$i][$j] = 0 Then
    ConsoleWrite(" ")
    ContinueLoop
    EndIf
    ConsoleWrite($aSudoku[$i][$j])
    Next
    ConsoleWrite("|"&@LF)
    Next
    ConsoleWrite("-------------"&@LF&@LF)
    EndFunc
    Func ReadSudoku($sFilePath)
    Local $aSudoku[9][9],$hFile,$sLine
    $hFile=FileOpen($sFilePath,0)
    For $i=0 To 8
    $sLine=FileReadLine($hFile)
    For $j=0 To 8
    $aSudoku[$i][$j]=Int(StringMid($sLine,$j+1,1))
    Next
    Next
    Return $aSudoku
    EndFunc
    Func SaveSudoku($sFilePath,$aSudoku)
    Local $hFile=FileOpen($sFilePath,2)
    For $i=0 To 8
    For $j=0 To 8
    FileWrite($hFile,$aSudoku[$i][$j])
    Next
    FileWrite($hFile,@CRLF)
    Next
    EndFunc

    [/autoit]
  • Übrigens würden mich auch Bemerkungen zu meine Code-Stil interessieren. Ich weiß, dass ich mehr Kommentare hätte schreiben können, aber dafür hatte ich noch keine Zeit :)
    Danke