I have written a function that generates a valid random sudoku board. Although, I am confused on why I need the i
loop.
If I remove this loop my program no longer runs correctly. Once it hits an invalid position (backtracks) it ends all together.
In most implementations, the i
is checked to see if it can be positioned at the free square. Although, I am using random numbers and not using this i
var.
Therefore why do I need this loop? Does my program return back to the iteration when backtracking?
// Creates a valid random BoardArray
func (board *Board) GenerateBoard(row int, col int) bool {
// get the next available pos on board
freePos := board.FreePos()
if freePos == nil {
// no more positions, done
return true
}
freeRow := freePos[0]
freeCol := freePos[1]
// generate random number
randNum := rand.Intn(10-1) + 1
rand.Seed(time.Now().UnixNano())
// this i loop is the confusion?
for i := 0; i <= 8; i++ {
// check if we can place at freePos
if board.ValidPos(randNum, freeRow, freeCol) {
// valid, place
board.BoardArray[freeRow][freeCol] = randNum
// recursion
if board.GenerateBoard(freeRow, freeCol + 1) {
return true
} else {
// backtrack, set back to 0
board.BoardArray[freeRow][freeCol] = 0
}
}
}
return false
}
board/board.go
package board
import (
"fmt"
"math/rand"
"time"
)
type Board struct {
BoardArray [9][9]int
}
// Creates a valid random BoardArray
func (board *Board) GenerateBoard(row int, col int) bool {
// get the next available pos on board
freePos := board.FreePos()
if freePos == nil {
// no more positions, done
return true
}
freeRow := freePos[0]
freeCol := freePos[1]
// generate random number
randNum := rand.Intn(10-1) + 1
rand.Seed(time.Now().UnixNano())
for i := 0; i <= 8; i++ {
if board.ValidPos(randNum, freeRow, freeCol) {
board.BoardArray[freeRow][freeCol] = randNum
if board.GenerateBoard(freeRow, freeCol + 1) {
return true
} else {
board.BoardArray[freeRow][freeCol] = 0
}
}
}
return false
}
// Solves BoardArray (existing board)
func (board *Board) SolveBoard(cellVal int, row int, col int) bool {
// get the next available pos on board
freePos := board.FreePos()
if freePos == nil {
// no more positions, done
return true
}
freeRow := freePos[0]
freeCol := freePos[1]
for i := 1; i <= 9; i++ {
// board.PrintBoard()
// fmt.Printf("Checking: row:%d,col:%d,val:%d \n", freeRow, freeCol, i)
if board.ValidPos(i, freeRow, freeCol) {
// fmt.Printf("Valid! row:%d, col:%d, val:%d \n", freeRow, freeCol, i)
board.BoardArray[freeRow][freeCol] = i
if board.SolveBoard(i, freeRow, freeCol + 1) {
return true
}
board.BoardArray[freeRow][freeCol] = 0
}
}
return false
}
// Checks all valid pos funcs
// Returns true if valid
func (board *Board) ValidPos(cellVal int, row int, col int) bool {
isValidInRow := board.ValidPosInRow(cellVal, row)
isValidInCol := board.ValidPosInCol(cellVal, col)
isValidInSubGrid := board.ValidPosInSubGrid(cellVal, col, row)
if isValidInRow && isValidInCol && isValidInSubGrid {
return true
}
return false
}
// Checks next free pos on board
// Returns [row,col] of free pos
func (board *Board) FreePos() []int {
for row := 0; row < len(board.BoardArray); row++ {
for col := 0; col < len(board.BoardArray[row]); col++ {
if board.BoardArray[row][col] == 0 {
validPos := []int{row, col}
return validPos
}
}
}
return nil
}
// Check if cellVal can be placed in the row rowN
// Returns true if valid pos
func (board *Board) ValidPosInRow(cellVal int, row int) bool {
for i := 0; i < len(board.BoardArray[row]); i++ {
currentValue := board.BoardArray[row][i]
if currentValue == cellVal {
return false
}
}
return true
}
// Check if cellVal can be placed in the column colN
// Returns true if valid pos
func (board *Board) ValidPosInCol(cellVal int, col int) bool {
for i := 0; i < len(board.BoardArray[col]); i++ {
currentValue := board.BoardArray[i][col]
if currentValue == cellVal {
return false
}
}
return true
}
// Check if cellVal can be placed in the 3x3 subgrid
// Returns true if valid pos
func (board *Board) ValidPosInSubGrid(cellVal int, colN int, rowN int) bool {
rowStart := (rowN / 3) * 3
colStart := (colN / 3) * 3
// Go through the subgrid,
// check if any values are equal to cellVal
for row := rowStart; row < rowStart+3; row++ {
for col := colStart; col < colStart+3; col++ {
subGridCell := board.BoardArray[row][col]
if subGridCell == cellVal {
return false
}
}
}
return true
}
// Helper Method:
// Prints board nicely
func (board *Board) PrintBoard() {
for row := 0; row < len(board.BoardArray); row++{
fmt.Printf("row:%d \t", row)
for col := 0; col < len(board.BoardArray[row]); col++{
fmt.Printf("%d|", board.BoardArray[row][col])
}
fmt.Println()
}
}
main.go
package main
import (
"board"
)
func main() {
grid := [9][9]int{}
board := board.Board{BoardArray: grid}
board.GenerateBoard(0, 0)
board.PrintBoard()
}