A. Brown
A. Brown

Reputation: 1

Sudoku puzzle in Python

I'm new to python and StackOverflow and trying to write a small program that checks if a sudoku puzzle (i.e. a series of lists) is correct (True) or incorrect (False).

So I broke it down by writing 2 functions, one that checks ROWS (i.e. checks that there is one of EACH number from 1-n - where n is the length of the list - in each list) and one function that checks COLUMNS (to make sure there is no crossover of elements down the lists, and that there is only one of each number from 1-n in position 0, 1, and so forth).

The first function is working fine, but the second one (checking columns) seems to constantly output 'True' even when the puzzle is incorrect. For example, for the list
myList =
[[1,2,3],
[3,1,2],
[3,2,3]],
the output is True, when the puzzle is wrong. I have tried to spot the problem lots of times by going through with e.g.s line by line, but to no avail! Can anyone spot what it is I've done wrong, or share any better ways of coding a sudoku-checker? :)
Thank you!! Here is my code for checking columns:

def check_down(list_of_lists):
a = []   #checking list
i = -1   #list
j = 0    #position
n = len(list_of_lists)
while True:
    i = i + 1
    if [list_of_lists[i][j]] in a: #if list element already in a, it is a copy so False
        return False
        break
    elif [list_of_lists[i][j]] not in a:
        a = a + [list_of_lists[i][j]] #if list element not in a then add it
        if i == n-1 and j == n-1: #if loop reaches end of lists, True
                return True
                break
        elif i == n-1 and j!= n-1: #if last list but not last position, move on
                j = j +1           #next position to check
                i = -1             #reset i to -1
                del a[:]           #empty the checking list
    else:
        return False

Upvotes: 0

Views: 1171

Answers (2)

Shasha99
Shasha99

Reputation: 1916

The problem in your code is that you are checking the existence of a list in list a instead of checking the existence of the number:

if [list_of_lists[i][j]] in a:

So the brackets around list_of_lists[i][j] are making it a list which contains single element. So you need to remover those brackets and the code will work as expected.

There are several other improvents as mentioned by @Right Leg.

However your logic for Sudoku checker is still wrong as you are missing the grid check. Checking the uniqueness at row level as well as at column level is a necessary condition but it is not sufficient. Consider the following example:

enter image description here enter image description here

enter image description hereenter image description here

As you can see in the images above, each row has unique elements, each column has unique elements, but there is duplicacy of elements in each 3x3 grid. So even if the answer is False, your solution will return True beacuse you do not have any grid check. So you need to write logic to check uniqueness at grid level as well.

You may use the following code. Note that the following code can be improved by using extra space:

import math

def checkSudoku(sudoku):
    # Check uniqueness in each row.
    for i in range(len(sudoku)):
        lst = []
        for j in range(len(sudoku)):
            if sudoku[i][j] in lst:
                return False
            else:
                lst.append(sudoku[i][j])

    # Check uniqueness in each column.
    for j in range(len(sudoku)):
        lst =[]
        for i in range(len(sudoku)):
            if sudoku[i][j] in lst:
                return False
            else:
                lst.append(sudoku[i][j])

    # Check uniqueness in each grid.
    offset = int(math.sqrt(len(sudoku)))
    for rowStart in range(0,len(sudoku),offset):
        rowEnd = rowStart + offset
        for columnStart in range(0,len(sudoku),offset):
            columnEnd = columnStart + offset

            lst = []
            for i in range(rowStart,rowEnd):
                for j in range(columnStart,columnEnd):
                    if sudoku[i][j] in lst:
                        return False
                    else:
                        lst.append(sudoku[i][j])

    # No test was failed, So return True.     
    return True

Upvotes: 0

Right leg
Right leg

Reputation: 16720

First off, your flow is really wrong.

You really should not write things like

while True :
    i = i + 1

even if the inside of the while is supposed to break somewhere. Instead, since you are iterating over the rows, just do:

while i < rowsNumber :
    i = i + 1

Then, you write:

if A :
    #stuff
elif not A :
    #other stuff
else :
    #guess what, stuff

But that last else cannot logically be reached. The right way is:

if A :
    #stuff
else :
    #other stuff

Besides, you write a = a + [list_of_lists[i][j]], which does work, but I would largely prefer a.append(list_of_list[i][j], which is way more pythonic.

Also, you don't need to use break after a return statement, because return stops the execution of the function.

Now for your problem: you wrote [list_of_lists[i][j]] in a, which is False, because [list_of_lists[i][j]] is a list. What you want is [list_of_lists[i][j]] in a, without the brackets.

I corrected this and tried it on your example, and it did return False.

Upvotes: 1

Related Questions