Basic Sudoku checker

Question:

I am creating a basic sudoku checker with the help of Python.
However, the result is always displayed as ‘False’.
The code is as follows:

list = [[1,2,3,4],
        [2,4,1,3],
        [3,1,4,2],
        [4,3,2,1]]

def sudoku_check(list):
    n = len(list)
    digit = 1
    while digit <= n:
        row_count = 0
        col_count = 0
        v = 0
        while v < n:
            x = 0
            while x < n:
                print ("Check")
                if digit == list[v][x]:
                    row_count = row_count + 1
                if digit == list[x][v]:
                    col_count = col_count + 1
                x = x + 1
            v = v + 1
        if col_count != 1 or row_count != 1:
            return False
        digit = digit + 1
    return True

print (sudoku_check(list))

I am new to programming. Would appreciate your help on this.
Thanks

Asked By: Shreyash Karnik

||

Answers:

Alright, have a solution for you/can explain your problem @ShreyashKarnik!

The Problem:

The issue in code comes from the chunk below:

while digit <= n:
    row_count = 0
    col_count = 0
    v = 0
    while v < n:
        x = 0
        while x < n:
            print ("Check")
            if digit == sudo_board[v][x]:
                row_count = row_count + 1
            if digit == sudo_board[x][v]:
                col_count = col_count + 1
            x = x + 1
        v = v + 1
    if col_count != 1 or row_count != 1:
        return False

So what exactly is this code doing? It’s going through every cell in your sudoku board and looking for a digit. For the sake of explanation, let’s say it’s looking for the digit 1. It checks every cell in the entire board, and since 1 appears 4 times total, col_count and row_count will be 4 every time. You can verify this with a print statement if you’d like!

Since your false check is checking against the number 1, it’s going to fail every time. So let’s start looking for a fix!

Making Things Pythonic

"Pythonic means code that doesn't just get the syntax right but that follows the conventions of the Python community". You say you’re new to programming, so learning the proper style of how to write python is important. You have a couple of issues in the code above:

  • Confusing variable names
  • Using while loops instead of for loops
  • Lack of code modularity

Let’s start with the last comment, lack of modularity and fix the other things along the way. Determining if a Sudoku grid is valid is actually surprisingly complex — it has three components.
1. Do all of the rows have the right number of digits?
2. Do all of the columns have the right number of digits?
3. Does the grid as a whole have the right number of digits?

3 is actually a factor of 1 and 2, which you figured out in your code — nice! But it might make things easier to read if we broke the first and second bit of things into their own functions. How might those look? Let’s do rows first. For our function, we’ll check each row and confirm that it has the right number of digits.

Let’s start with the row checker. All we have to do for that is the following:

def has_correct_number_rows(sudo_board):
    # the set we create below is an unordered grouping of the numbers
    # 1-4.
    correct_set = set(range(1, len(sudo_board)))
    for row in sudo_board:
        # this if statement checks if our row contains values 1-4
        if (correct_set != set(row)):
            return False
    return True

This will return True if the rows all contain the correct number of items, otherwise it will give false.

Next, the checking the correct number of columns. This is slightly more complicated, but still fairly simple:

def has_correct_number_cols(sudo_board):
    correct_set = set(range(1, len(sudo_board) + 1))
    for col_num in range(0, len(sudo_board)):
        # col_set creates a set of the elements in a given column
        col_set = set([row[col_num] for row in sudo_board])
        if (correct_set != set(row)):
            return False
    return True

Same return values here.

Putting it all together

Now that you have these two functions, your final check is actually very easy. It’s below:

def sudoku_check_peter(sudo_board):
    correct_rows = has_correct_number_rows(sudo_board)
    correct_cols = has_correct_number_cols(sudo_board)
    # This last line returns True if both are true, otherwise
    # False.
    return correct_rows and correct_cols

This ended up being quite wordy which I apologize for — happy to answer follow up questions or explain anything more! hope this helps.

Answered By: Peter Dolan
sudoku_correct =[[8,3,5,4,1,6,9,2,7],
               [2,9,6,8,5,7,4,3,1],
               [4,1,7,2,9,3,6,5,8],
               [5,6,9,1,3,4,7,8,2],
               [1,2,3,6,7,8,5,4,9],
               [7,4,8,5,2,9,1,6,3],
               [6,5,2,7,8,1,3,9,4],
               [9,8,1,3,4,5,2,7,6],
               [3,7,4,9,6,2,8,1,5]]

sudoku_incorrect =[[8,3,5,4,1,6,9,2,7],
                 [2,9,6,8,5,7,4,3,1],
                 [4,1,7,2,9,3,6,5,8],
                 [5,6,9,1,3,4,7,8,2],
                 [1,2,3,6,7,8,5,4,9],
                 [7,4,8,5,2,9,1,6,3],
                 [6,5,2,7,8,1,3,9,4],
                 [9,8,1,3,4,5,2,7,6],
                 [3,7,4,9,6,2,8,1,1]]

test=[1,2,3,4,5,6,7,8,9]

def isvalid(s):
    for i in range(9):
        s1=[s[i][j] for j in range(9)]
        s1.sort()
        if test!=s1:
            return False
        s2=[s[j][i] for j in range(9)]
        s2.sort()
        if test!=s2:
            return False
        k=(i // 3)*3
        l=(i % 3)*3
        s3=[s[m][n] for m in range(k,k+3) for n in range(l,l+3)]
        s3.sort()
        if test!=s3:
            return False
    return True

this is a simple checker for a proposed sudoku solution. it checks that every line, row and block is filled with all 9 different digits

Answered By: Alex B
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.