Fun with Sudoku
Posted: Mon Jun 05, 2006 3:15 am
Hi all,
Just messing around with the new version and indulging a (hopefully short-lived) fascination with Sudoku.
Anyway, I was trying to come up with an elegant way of generating valid Sudoku grids with little success because I didn't think of recursion. So here is a completely inelegant generator that's fast nonetheless - based on some brute force pseudocode posted in a Sudoku programming forum.
Now that I've got this working I'm going to try to add recursion to my 'more refined' original attempt. Not that it matters that much - the ogre method presented here usually busts through it in couple tenths of a second. Ah, CPU power, the downfall of thoughtful code.
So, thought this might be helpful to someone.
Just messing around with the new version and indulging a (hopefully short-lived) fascination with Sudoku.
Anyway, I was trying to come up with an elegant way of generating valid Sudoku grids with little success because I didn't think of recursion. So here is a completely inelegant generator that's fast nonetheless - based on some brute force pseudocode posted in a Sudoku programming forum.
Now that I've got this working I'm going to try to add recursion to my 'more refined' original attempt. Not that it matters that much - the ogre method presented here usually busts through it in couple tenths of a second. Ah, CPU power, the downfall of thoughtful code.
So, thought this might be helpful to someone.
Code: Select all
; sudoku.pb
; Main program file
; Include files
XIncludeFile"grid.pb" ; Board functions
; Main Loop
If OpenConsole()
EnableGraphicalConsole(1)
ClearConsole()
; Print title
ConsoleLocate(2, 1)
Print("Sudoku Test")
; Make grid
StartTime = ElapsedMilliseconds()
MakeGrid()
ElapsedTime = ElapsedMilliseconds()-StartTime
; Print grid
ConsoleLocate(1, 2)
Print("Finished Grid")
For i = 0 To 80
ConsoleLocate(3+i%9, 4+Round(i/9,0))
Print(Str(bGrid(i)))
Next i
; Print time
ConsoleLocate(1, 16)
Print("Time: " + Str(ElapsedTime) + "ms")
; Exit when ready
ConsoleLocate(1, 18)
Print("<<Hit a Key>>")
Input()
CloseConsole()
EndIf
End
; IDE Options = PureBasic v4.00 (Windows - x86)
; CursorPosition = 45
; FirstLine = 6
; Folding = -
Code: Select all
; grid.pb
; Sudoku grid functions
; Declare global variables
Global Dim bGrid.b(81)
; Declare functions
Declare MakeGrid() ; Main grid constructor
Declare.b MakeCell(index.b) ; Recursive cell filler
Declare.b CheckGrid() ; Validates grid (ignores zeros)
; Procedure MakeGrid()
; Fill in the board array with a valid Sodoku grid.
; Recursively call MakeCell() and wait for success.
Procedure MakeGrid()
; Kick off recursive generation
MakeCell(0)
EndProcedure
; Procedure.b MakeCell(index.b)
; Try numbers in a particular cell. When a possible match
; is found move on to next cell. If no solution works
; fail back to previous level.
Procedure.b MakeCell(index.b)
; Procedure variables
Static Dim CellOrder.b(9)
; Check for completion
If index = 81
; The board is full, we're done!
ProcedureReturn 1
EndIf
; Set random order to try numbers
For i = 1 To 9
CellOrder(i) = i
Next i
For i = 1 To 25
Swap CellOrder(Int(Random(8)+1)), CellOrder(Int(Random(8)+1))
Next i
For i = 1 To 9
bGrid(index) = CellOrder(i)
If CheckGrid() = 1
If MakeCell(index+1) = 1
ProcedureReturn 1
EndIf
EndIf
Next i
bGrid(index) = 0
ProcedureReturn -1
EndProcedure
; Procedure.b CheckGrid()
; Validate grid by ensuring that the numbers one through
; nine only appear once in each row, column, and quadrant.
Procedure.b CheckGrid()
; Procedure variables
Protected Dim Counts(9)
; Check columns
For row = 0 To 8
For col = 0 To 8
If bGrid(row*9+col) > 0
; Add number here to count
Counts(bGrid(row*9+col)) = Counts(bGrid(row*9+col)) + 1
; If there's more than one then fail
If Counts(bGrid(row*9+col)) > 1
ProcedureReturn -1
EndIf
EndIf
Next col
; Clear counts
For i = 0 To 9
Counts(i) = 0
Next i
Next row
; Check rows
For col = 0 To 8
For row = 0 To 8
If bGrid(row*9+col) > 0
; Add number here to count
Counts(bGrid(row*9+col)) = Counts(bGrid(row*9+col)) + 1
; If there's more than one then fail
If Counts(bGrid(row*9+col)) > 1
ProcedureReturn -1
EndIf
EndIf
Next row
; Clear counts
For i = 0 To 9
Counts(i) = 0
Next i
Next col
; Check quadrants
For quad = 0 To 8
Select quad
Case 0, 3, 6
bx = 0
Case 1, 4, 7
bx = 3
Default
bx = 6
EndSelect
Select quad
Case 0, 1, 2
by = 0
Case 3, 4, 5
by = 3
Default
by = 6
EndSelect
For row = 0 To 2
For col = 0 To 2
If bGrid((by+row)*9+bx+col) > 0
; Add number here to count
Counts(bGrid((by+row)*9+bx+col)) = Counts(bGrid((by+row)*9+bx+col)) + 1
; If there's more than one then fail
If Counts(bGrid((by+row)*9+bx+col)) > 1
ProcedureReturn -1
EndIf
EndIf
Next col
Next row
; Clear counts
For i = 0 To 9
Counts(i) = 0
Next i
Next quad
; We passed all of the tests
ProcedureReturn 1
EndProcedure
; IDE Options = PureBasic v4.00 (Windows - x86)
; CursorPosition = 16
; Folding = 5