Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Diana - SolveSudoku solution #156

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions sudoku.go
Original file line number Diff line number Diff line change
@@ -1 +1,77 @@
package main

func SolveSudoku(board [][]int) [][]int {
Solver(board, 0, 0)
return board
}

// determine if there is a valid entry for this cell and all remaining empty cells
// assumption: a valid solution exists for the input board
func Solver(board [][]int, x int, y int) bool {
// base case: we already checked the last cell (8,8) which was valid
if x == 0 && y == 9 {
return true
}
// cell content != 0 means it's fixed, so move onto the next cell
if board[y][x] != 0 {
x, y = GetNext(x, y)
return Solver(board, x, y)
}
if board[y][x] == 0 {
// increment through 1-9 for this cell, and return
for i := 1; i <= 9; i++ {
board[y][x] = i
if CheckCell(board, x, y) {
xn, yn := GetNext(x, y)
if Solver(board, xn, yn) {
return true
}
// otherwise, the board is not valid with this current value
// continue incrementing
}
}
// all values 1-9 for this cell are invalid, so reset this cell
// the 'previous' cell should increment itself
board[y][x] = 0
}
return false
}

func GetNext(x int, y int) (int, int) {
x++
// if we are at the end of a row, 'loop around' to the next
if x > 8 {
y++
x = 0
}
return x, y
}

// check in this row, column, and 3x3 square that no other value
// is equal to board[y][x]
func CheckCell(board [][]int, x int, y int) bool {
current := board[y][x]
// check columns and rows, skipping the current cell
for i := 0; i <= 8; i++ {
if i != y && board[i][x] == current {
return false
}
if i != x && board[y][i] == current {
return false
}
}
// 'round down' to the top left cell in the nearest 3x3 grid
lowx := x - (x % 3)
lowy := y - (y % 3)
// check the current value is not repeated in the local 3x3 grid
for xi := lowx; xi < lowx+3; xi++ {
for yi := lowy; yi < lowy+3; yi++ {
if xi != x && yi != y {
if board[yi][xi] == current {
return false
}
}
}
}
return true
}
35 changes: 34 additions & 1 deletion sudoku_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,37 @@ func TestSolveSudoku(t *testing.T) {
if !reflect.DeepEqual(solved, expected) {
t.Errorf("Sudoku puzzle was not solved correctly. Expected:\n%v\n\nGot:\n%v", expected, solved)
}
}
}

// Tries the slow board listed on https://en.wikipedia.org/wiki/Sudoku_solving_algorithms
func TestSolveSudokuSlow(t *testing.T) {
input := [][]int{
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 3, 0, 8, 5},
{0, 0, 1, 0, 2, 0, 0, 0, 0},
{0, 0, 0, 5, 0, 7, 0, 0, 0},
{0, 0, 4, 0, 0, 0, 1, 0, 0},
{0, 9, 0, 0, 0, 0, 0, 0, 0},
{5, 0, 0, 0, 0, 0, 0, 7, 3},
{0, 0, 2, 0, 1, 0, 0, 0, 0},
{0, 0, 0, 0, 4, 0, 0, 0, 9},
}

expected := [][]int{
{9, 8, 7, 6, 5, 4, 3, 2, 1},
{2, 4, 6, 1, 7, 3, 9, 8, 5},
{3, 5, 1, 9, 2, 8, 7, 4, 6},
{1, 2, 8, 5, 3, 7, 6, 9, 4},
{6, 3, 4, 8, 9, 2, 1, 5, 7},
{7, 9, 5, 4, 6, 1, 8, 3, 2},
{5, 1, 9, 2, 8, 6, 4, 7, 3},
{4, 7, 2, 3, 1, 9, 5, 6, 8},
{8, 6, 3, 7, 4, 5, 2, 1, 9},
}

solved := SolveSudoku(input)

if !reflect.DeepEqual(solved, expected) {
t.Errorf("Sudoku puzzle was not solved correctly. Expected:\n%v\n\nGot:\n%v", expected, solved)
}
}
Loading