-1

I am trying to solve a sudoku puzzle in Go using a recursive backtracking algorithm. I created helper functions that check if a certain row, column, or block are valid (i.e no repeated values), as well as a function to print out the current state. I have tested all of these many times so I don't think they are causing the issue. I created the following function to test if a potential game board would be possible.

func cellValid(gameBoard *[9][9]int, value int, y int, x int) bool {
    oldVal := gameBoard[y-1][x-1]
    gameBoard[y-1][x-1] = value
    row := getRow(gameBoard, y)
    col := getCol(gameBoard, x)
    block := getBlock(gameBoard, x, y)
    possible := unitValid(row) && unitValid(col) && unitValid(block)
    gameBoard[y-1][x-1] = oldVal
    return possible
}

It makes a change to the gameboard, checks if it is possible and stores that bool in the variable possible. It changes the board back to what it was then returns the bool. This function is being called from the following solveBoard function.

func solveBoard(gameBoard *[9][9]int) {
    for row := 1; row <= 9; row++ {
        for col := 1; col <= 9; col++ {
            if gameBoard[row-1][col-1] == 0 {
                for value := 1; value <= 9; value++ {
                    if cellValid(gameBoard, value, row, col) {
                        gameBoard[row-1][col-1] = value
                        solveBoard(gameBoard)
                        gameBoard[row-1][col-1] = 0
                    }
                }
                return
            }
        }
    }
    printBoard(gameBoard)
    return
}

Upon running the file I get no output.

func main() {
    var gameBoard = [9][9]int{
        {5, 3, 0, 0, 7, 0, 0, 0, 0},
        {6, 0, 0, 1, 9, 5, 0, 0, 0},
        {0, 9, 8, 0, 0, 0, 0, 6, 0},
        {8, 0, 0, 0, 6, 0, 0, 0, 3},
        {4, 0, 0, 8, 0, 3, 0, 0, 1},
        {7, 0, 0, 0, 2, 0, 0, 0, 6},
        {0, 6, 0, 0, 0, 0, 2, 8, 0},
        {0, 0, 0, 4, 1, 9, 0, 0, 5},
        {0, 0, 0, 0, 8, 0, 0, 7, 9}}

    solveBoard(&gameBoard)
}

Here is a link to a go playground containing all my code. Go Playground

The following video demonstrates what I am trying to accomplish in python.

Computerphile Video

Solution to puzzle: Puzzle solution

  • Looks interesting. To help you could create a golang playground link. – Norbert Feb 18 '20 at 04:07
  • @NorbertvanNobelen Good Idea, I've added it. –  Feb 18 '20 at 04:09
  • 2
    Line 101, `return` statement. `printBoard` never gets reached – Denis Sheremet Feb 18 '20 at 04:11
  • 1
    Newermind, I didn't get how it supposed to work at the first glance. Anyway, try going through it in debugger to see what goes wrong – Denis Sheremet Feb 18 '20 at 04:13
  • @DenisSheremet It is the cause of not printing the board. Removing it, returns a lot of board prints, if it is correct is good question :) – Norbert Feb 18 '20 at 04:17
  • The described behavior is possible if cellValid returns false for all 9 values. – Burak Serdar Feb 18 '20 at 04:17
  • The idea is that cellValid returns false for all values 1 through 9 when it reaches a point when the current grid is no longer solvable. When this happens the return on line 101 is executed, resuming execution on line 98 setting the game board to 0. This keeps repeating until it can make it all the way through. It goes back and checks its work, gradually building up what it knows to be possible until it is all possible and it is solved. –  Feb 18 '20 at 04:22
  • 1
    I think you are expecting arrays to be passed by reference (eg restoring the array copy using oldVal is not nec. in the 2nd last line of cellValid) In Go arrays are passed by value. Try passing a pointer to the array. BTW good luck - I hope it goes well ;) – AJR Feb 18 '20 at 04:33
  • @AJR Admittedly my understanding of pointers is not the best. I have tried this by changing the initial call on line 121 to changeBoard(&gameBoard) and updated all functions to have gameBoard *[9][9]int instead of gameBoard [9][9]int. From my understanding this means that a pointer to the inital game board is being passed around instead of by value. This still is giving no output. –  Feb 18 '20 at 04:34
  • @Ben OK but I think it is an improvement. – AJR Feb 18 '20 at 04:36
  • @AJR I agree, thank you. –  Feb 18 '20 at 04:39
  • I think the original algorithm is safe for pass-by-value semantics. – Burak Serdar Feb 18 '20 at 04:43
  • For one thing: the row and cols are mixed up in cellValid: you're using rows in place of cols. – Burak Serdar Feb 18 '20 at 05:03
  • @BurakSerdar Nice catch. I updated it. Still no output, unfortunately. –  Feb 18 '20 at 05:22
  • Same goes for blocks: rows and cols are mixed up, you're looking at the wrong block. – Burak Serdar Feb 18 '20 at 05:34
  • @BurakSerdar No, that one is correct. X represents the column, Y represents the row. –  Feb 18 '20 at 05:54
  • No it is not. Print game table and see. When it changes an element in the first row third column, the block it checks is the one on the first three-colums, rows 7-9. – Burak Serdar Feb 18 '20 at 06:05
  • @BurakSerdar I've tried with the changes and none the less still no output. I appreciate the feedback. –  Feb 18 '20 at 08:36

2 Answers2

0

Your program works perfectly fine. Double check the second last line of your matrix:

You have:

{0, 0, 0, 4, 1, 7, 0, 0, 5},

But it should be

{0, 0, 0, 4, 1, 9, 0, 0, 5},
guenhter
  • 11,255
  • 3
  • 35
  • 66
0

The final working code is.

package main

import (
    "fmt"
)

func printBoard(gameBoard *[9][9]int) {
    for y := 0; y < 9; y++ {
        if y == 3 || y == 6 {
            fmt.Println("\n---------")
        } else {
            fmt.Println("")
        }
        for x := 0; x < 9; x++ {
            if x == 3 || x == 6 {
                fmt.Print("|", gameBoard[y][x])
            } else {
                fmt.Print("", gameBoard[y][x])
            }
        }
    }
    fmt.Println("")
}

func unitValid(unit [9]int) bool {
    for value := 1; value <= 9; value++ {
        count := 0
        for index := 0; index < 9; index++ {
            if unit[index] == value {
                count++
            }
        }
        if count > 1 {
            return false
        }
    }
    return true
}

func getRow(gameBoard *[9][9]int, row int) [9]int {
    return gameBoard[row-1]
}

func getCol(gameBoard *[9][9]int, col int) [9]int {
    var column [9]int
    for row := 0; row < 9; row++ {
        column[row] = gameBoard[row][col-1]
    }
    return column
}

func getBlock(gameBoard *[9][9]int, row, col int) [9]int {
    i := whatBlock(col)*3 - 2
    j := whatBlock(row)*3 - 2
    var block [9]int
    block[0] = gameBoard[j-1][i-1]
    block[1] = gameBoard[j-1][i]
    block[2] = gameBoard[j-1][i+1]
    block[3] = gameBoard[j][i-1]
    block[4] = gameBoard[j][i]
    block[5] = gameBoard[j][i+1]
    block[6] = gameBoard[j+1][i-1]
    block[7] = gameBoard[j+1][i]
    block[8] = gameBoard[j+1][i+1]
    return block
}

func whatBlock(val int) int {
    if val >= 1 && val <= 3 {
        return 1
    } else if val >= 4 && val <= 6 {
        return 2
    } else if val >= 7 && val <= 9 {
        return 3
    }
    return 0
}

func cellValid(gameBoard *[9][9]int, value int, y int, x int) bool {
    oldVal := gameBoard[y-1][x-1]
    gameBoard[y-1][x-1] = value
    row := getRow(gameBoard, y)
    col := getCol(gameBoard, x)
    block := getBlock(gameBoard, y, x)
    possible := unitValid(row) && unitValid(col) && unitValid(block)
    gameBoard[y-1][x-1] = oldVal
    return possible
}

func solveBoard(gameBoard *[9][9]int) {
    for row := 1; row <= 9; row++ {
        for col := 1; col <= 9; col++ {
            if gameBoard[row-1][col-1] == 0 {
                for value := 1; value <= 9; value++ {
                    if cellValid(gameBoard, value, row, col) {
                        gameBoard[row-1][col-1] = value
                        solveBoard(gameBoard)
                        gameBoard[row-1][col-1] = 0
                    }
                }
                return
            }
        }
    }
    printBoard(gameBoard)
    return
}

func main() {
    var gameBoard = [9][9]int{
        {5, 3, 0, 0, 7, 0, 0, 0, 0},
        {6, 0, 0, 1, 9, 5, 0, 0, 0},
        {0, 9, 8, 0, 0, 0, 0, 6, 0},
        {8, 0, 0, 0, 6, 0, 0, 0, 3},
        {4, 0, 0, 8, 0, 3, 0, 0, 1},
        {7, 0, 0, 0, 2, 0, 0, 0, 6},
        {0, 6, 0, 0, 0, 0, 2, 8, 0},
        {0, 0, 0, 4, 1, 9, 0, 0, 5},
        {0, 0, 0, 0, 8, 0, 0, 7, 9}}

    solveBoard(&gameBoard)
}