Python sudoku checker

Question:

I’m working on an assignment for my CIS class in python. We have to code a Sudoku checker. In a 9×9 board we obviously have to check each row, col and 3×3 square for duplicates. I’m a little stuck on the idea of how to check the numbers by a 3×3 square. Below is my code for checking each row and col, if someone could help me a little with an outline or an approach just something for checking each 3×3 square that would be amazing!

self.columns = [ ]
     for col in range(9):
        col_tiles = [ ]
        self.columns.append(col_tiles)
        for row in range(9):
            col_tiles.append(self.tiles[row][col])
self.squares = [ ]
for col in range(1, 10, 3):
        for row in range(1, 10, 3):
            square_tiles = [ ]
            self.squares.append(square_tiles)
            for x in range(3):
                for y in range(3):
                    square_tiles.append(self.tiles[x][y])
Asked By: user1758231

||

Answers:

Here’s what I would do: create 3 dictionaries, one for the rows, one for the columns, and one for the 3×3 squares.

while you loop through each element in the sudoku puzzle, keep track of your row and column (trivial), and use if statements to keep track of which 3×3 square you’re in (a bit more involved)

then just send each element to the corresponding row, column, and 3×3 square dictionary, and compare at the end.

This way you only need to inspect each element once.

EDIT: also, set will probably be useful

Answered By: Cameron Sparr

Whenever you’re having trouble coming up with an algorithm, just ask yourself: “How would I solve this manually, if the only way I could be given the problem was by a computer“.

In other words, if I asked you to check the top left 3×3 grid, your eyes would just go to the top left corner and add up numbers. But if I said, check the top left 3×3 grid, and didn’t actually give you the board, you’d say, “OK, give me the top left 3×3 grid”.

And I’d say “How?”

And you’d say, “Imagine the tiles are numbered by rows and columns. I want the tiles in spots (0,0), (0,1), (0,2), (1,0), (1,1), (1,2), (2,0), (2,1), and (2,2)”

Does that help?

Answered By: ckhan

This assumes you have the freedom to read the data and structure how you want. We want a set of unique values 1-9 for each row/column/3×3 grid, so one way is to either use a set or a list comparison (we’ll use set here to make it cleaner). If we create a set equal to the numbers from 1 to 9, we have a point against which we can compare all of our other groups. Assume a structure like this (from here):

In [1]: r1 = [9,3,2,5,4,8,1,7,6]

In [2]: r2 = [1,8,7,9,2,6,5,4,3]

In [3]: r3 = [5,4,6,3,7,1,2,8,9]

# Continues....

Where each row represents a full row of data. Now lets create a section of that data that represents the first three rows, pull out one grid and compare the contents to our set:

In [4]: sec1 = [r1, r2, r3]

In [5]: nums = set(range(1, 10))

In [6]: nums == set(n for row in sec1 for n in row[:3])
Out[6]: True

This iterates over the first three rows and returns the first three elements in each of those rows. To get a better visual, here is the equivalent for-loop code to make it a bit easier to decipher:

result = set()
for row in sec1:
    for n in row[:3]:
      result.add(n)

Since our set of numbers includes everything from 1-9, we know it is valid. To move to the second, we range the row[:3] to row[3:6] (and row[6:9] after that). You’ll then need to handle this for the next two sections as well. I’ll leave it to you as to how to wrap this in a more dynamic structure (note the multiples of three), but hopefully this will get you started 🙂

Answered By: RocketDonkey

This function will do. “sample” gives the randomness, so every time you run this you will get a different one.

from random import sample
def generate_sudoku_checker():
    random_list = sample([1,2,3,4,5,6,7,8,9],9)
    random_list = random_list + random_list[:9]
    for i in range(3):
        for j in range(3):
            print(random_list[i+j*3:i+j*3+9])
Answered By: Shibashis

Here is my solution to this :

Funtion:

def check_sudoku(lis):
    n = len(lis)
    digit = 1  #start from one
    while (digit<=n):
        i=0
        while i<n:  # go through each row and column
            row_count=0
            column_count=0
            j=0
            while j < n: # for each entry in the row / column
                if lis[i][j] == digit: # check row count
                    row_count = row_count+1
                if lis[j][i]== digit :
                   column_count = column_count+1

             j=j+1
           if row_count !=1 or column_count!=1:
             return False
           i=i+1 # next row/column
        digit = digit+1 #next digit
return True
Answered By: Faheem

Late to the party but this worked for me:

def insert_sudoku():
 puzzle = []
 for i in range(9):
     print("You've entered", len(puzzle), "rows so far")
     row = input("Enter a row")
     if len(row) < 9:
         print("Not enough numbers on this row")
         return insert_sudoku()
     elif len(row) > 9:
         print("Too many numbers. Try again!")
         return insert_sudoku()

    try:
        row = [int(dig) for dig in row]
        puzzle.append(row)
    except:
        print("Whoops, looks like you didn't enter only numbers somewhere. Try again!")
        return insert_sudoku()

validate_entries(puzzle)

def validate_entries(puzzle):

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

 b1, b2, b3, b4, b5, b6, b7, b8, b9 = [], [], [], [], [], [], [], [], []

 for i in range(9):
    z = []
    for x in range(9):
        z.append(puzzle[i][x])
    puzzle.append(z)

 for i in range(3):
    b1 += (puzzle[i][:3])
    b4 += (puzzle[i][3:6])
    b7 += (puzzle[i][6:])

 for i in range(3,6):
    b2 += (puzzle[i][:3])
    b5 += (puzzle[i][3:6])
    b8 += (puzzle[i][6:])

 for i in range(6,9):
    b3 += (puzzle[i][:3])
    b6 += (puzzle[i][3:6])
    b9 += (puzzle[i][6:])

 puzzle.append(b1)
 puzzle.append(b2)
 puzzle.append(b3)
 puzzle.append(b4)
 puzzle.append(b5)
 puzzle.append(b6)
 puzzle.append(b7)
 puzzle.append(b8)
 puzzle.append(b9)

 for iter in puzzle:
     if sorted(iter) != check:
         print("No")
         return

     print("Yes")

 insert_sudoku()

Inspired by this article

EDIT: Indentation might be off from copy + pasting the code.

Answered By: Reagan Yego

What my answer adds is the use of a list comprehension to extract the tiles from the board.

    """
    # good
    board=[
    [2,9,5,7,4,3,8,6,1],
    [4,3,1,8,6,5,9,2,7],
    [8,7,6,1,9,2,5,4,3],
    [3,8,7,4,5,9,2,1,6],
    [6,1,2,3,8,7,4,9,5],
    [5,4,9,2,1,6,7,3,8],
    [7,6,3,5,2,4,1,8,9],
    [9,2,8,6,7,1,3,5,4],
    [1,5,4,9,3,8,6,7,2]
    ]
    """
    # bad
    board = [
    [1,9,5,7,4,3,8,6,2],
    [4,3,1,8,6,5,9,2,7],
    [8,7,6,1,9,2,5,4,3],
    [3,8,7,4,5,9,2,1,6],
    [6,1,2,3,8,7,4,9,5],
    [5,4,9,2,1,6,7,3,8],
    [7,6,3,5,2,4,1,8,9],
    [9,2,8,6,7,1,3,5,4],
    [2,5,4,9,3,8,6,7,1]
    ]
    
    def check(l):
        # each digit 1-9 should occur once 
        for n in range(1,10):
            try:
                l.index(n)
            except ValueError:
                return False
        return True
        
# check the rows
for row in board:
    print(check(row))
    
# check the columns
for column in [ [ board[r][c] for r in range(9) ] for c in range(9) ]:
    print(check(column))
    
# check the tiles
for tile in [[board[r][c] for r in range(row, row + 3) for c in range(col, col + 3)] for row in range(0, 9, 3) for col in range(0, 9, 3)]:
    print(check(tile))
Answered By: Clarius

This is my solution. I also want to confirm the time and space complexity of this code:

"""
Sample input 1:
295743861
431865927
876192543
387459216
612387495
549216738
763524189
928671354
154938672

Output: YES!

Sample input 2
195743862
431865927
876192543
387459216
612387495
549216738
763524189
928671354
254938671

Output: NOPE!!
"""
##################Solution############################################
def get_input():
    #Get the input in form of strings and convert into list
    print("Enter the board here: ")
    lines = []
    while True:
        line = input()
        if line:
            lines.append(line)
        else:
            break
        final = [(list(i)) for i in lines]
    return final


def row_check(board):
    # row check function which will be used in other two functions as well
    text = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
    x = True
    for row in board:
        if sorted(row) == text:
            x = True
        else:
            x = False
    return x


def col_check(board):
    # Getting the list of 9 lists containing column elements
    i = 0
    j = 0
    cols = [[], [], [], [], [], [], [], [], []]
    for j in range(0, 9):
        for i in range(0, 9):
            cols[j].append(board[i][j])
    return (row_check(cols))


def tile_check(board):
    #Getting the list of 9 lists converting each tile of 3x3 into 9 element list
    lst =[[],[],[],[],[],[],[],[],[]]
    i = 0
    j = 0
    k = 0
    while k<9:
        for r in range(i,i+3):
            for c in range(j, j+3):
                lst[k].append(board[r][c])
        j = j +3
        k = k +1
        if j == 9:
            j = 0
            i = i+3       
    return (row_check(lst))
        
#main program
c = get_input()
if row_check(c) and col_check(c) and tile_check(c):
    print("YES!")
else:
    print("NOPE!!")
Answered By: Niyati Joshi
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.