0

I started using my own method of solving Sudoku puzzles. I keep a list of every unused number in each row, column, and box. I then loop over my open list of unsolved squares looking for a square that either only has 1 possible number that could be placed there or a row, column, or box that only has one square that could hold a specific number. When I find a solution to another square I remove the number I just found from the row, column, and box that the square is a part of.

Okay, that all works. That's the majority of my solve() method. At the very end of that method if the the board is unsolved I call depthFirst(). This should go through the remaining unsolved squares using the backtracking technique.

This is the board I am using for testing:

400000805
030000000
000700000
020000060
000080400
000010000
000603070
500200000
104000000

I compared my code against this solution and I can't see too many differences. Algorithm for solving Sudoku

Does anybody have any idea why the backtracking portion of my code isn't working?

Thanks!

import copy

# Only removes the element from the list if it exists in the list
def safeRemove(l, e):
    if l.count(e) > 0:
        l.remove(e)

# Represents the board and keeps track of everything needed for solving the puzzle
class Sudoku:
    # 3x3 array of 3x3 arrays to represent the board
    # board is filled with BoardPos objects that keep track of the square's value, row, column, and box the square is a part of
    board = [[[[None for i in range(3)] for j in range(3)] for k in range(3)] for l in range(3)]
    # Keeps track of all numbers that are not currently taken in each row, column, and box
    rows = [[i for i in range(1, 10)] for j in range(9)]
    cols = [[i for i in range(1, 10)] for j in range(9)]
    boxes = [[i for i in range(1, 10)] for j in range(9)]
    # Unsolved squares
    openList = list()

    # Keeps track of each square's current value (0 for unsolved) and which
    # row, column, and box the square is a part of
    class BoardPos:
        def __init__(self, w, x, y, z):
            self.a = w
            self.r = x
            self.c = y
            self.b = z

    # Use an algorith similar to DFS to solve the remainder of the puzzle
    def depthFirst(self):
        if len(self.openList) == 0:
            self.board = boardState.board
            return True

        curSquare = self.openList[0]
        possibilities = self.getPossibilities(curSquare)

        # Save current state to return to
        tempBoard = copy.deepcopy(self.board)
        tempRows = copy.deepcopy(self.rows)
        tempCols = copy.deepcopy(self.cols)
        tempBoxes = copy.deepcopy(self.boxes)
        tempOpenList = copy.deepcopy(self.openList)

        for e in possibilities:
            self.found(curSquare, e)
            if self.depthFirst():
                return True

            # Restore to state of the last partial, possibile solution
            self.board = tempBoard
            self.rows = tempRows
            self.cols = tempCols
            self.boxes = tempBoxes
            self.openList = tempOpenList

        return False

    # Set the square the value found and remove that value from the square's
    # row, column, and box and remove the square from the open list
    def found(self, index, el):
        i, j, k, l = index
        self.board[i][j][k][l].a = el
        self.removeFound(index, el)
        del self.openList[0]

    # Remove the value from the square's row, column, and box
    def removeFound(self, index, el):
        i, j, k, l = index
        safeRemove(self.rows[self.board[i][j][k][l].r], el)
        safeRemove(self.cols[self.board[i][j][k][l].c], el)
        safeRemove(self.boxes[self.board[i][j][k][l].b], el)

    # Returns a list of all possible values for the square
    def getPossibilities(self, index):
        i, j, k, l = index
        tempRow = self.rows[self.board[i][j][k][l].r]
        tempCol = self.cols[self.board[i][j][k][l].c]
        tempBox = self.boxes[self.board[i][j][k][l].b]
        return list(set(tempRow) & set(tempCol) & set(tempBox))

    # Returns the box of the square
    def box(self, i, j, k, l):
        return i * 3 + j

    # Returns the row of the square
    def row(self, i, j, k, l):
        return i * 3 + k

    # Returns the column of the square
    def col(self, i, j, k, l):
        return j * 3 + l

def main():
    # Removed constructor to reduce code. Constructor just initialized the board with values from board.txt
    puzzle = Sudoku("board.txt")
    puzzle.depthFirst()
    puzzle.printBoard()

if __name__ == "__main__":
    main()
Community
  • 1
  • 1
janovak
  • 1,531
  • 2
  • 12
  • 22
  • 2
    That is way too much code for us to look through. Try to reduce your code until you find a minimal example that doesn't work as you'd expect. – orlp Mar 13 '15 at 17:19
  • I went through and removed all the code I think is not needed to understand the problem. – janovak Mar 13 '15 at 19:44

0 Answers0