Python Forum
[Tkinter] Sudoku solver with tkinter
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tkinter] Sudoku solver with tkinter
#1
Hello,

I've got coding experience but I'm new to python.

I'm trying to generate a sudoku solver in python using tkinter. I found online the code - now I'm trying to link it with tkinter. The code uses the list bo - this list contains the entered values from the entries of tkinter.

How to pass the list "bo" to the solve function when the button "readin" is pressed?

I tried " bo=readin() " (line 91).

Here is the error description:
Traceback (most recent call last):
File "d:/Ordner/Python/testgrid2/testgrid2.py", line 91, in <module>
bo=readin()
File "d:/Ordner/Python/testgrid2/testgrid2.py", line 70, in readin
listrow0.append(Square[i].get())
IndexError: list index out of range

What I am doing wrong?

Thanks for your help!!

Greetings,

flash77

import tkinter as tk
from tkinter import Entry, IntVar, Tk

def solve(bo):
    find = find_empty(bo)
    if not find:
        print("Sudoku solved.")
        return True
    else:
        row, col = find

    for i in range(1,10):
        if valid(bo, i, (row, col)):
            bo[row][col] = i

            if solve(bo):
                return True

            bo[row][col] = 0

    return False

def valid(bo, num, pos):
    # Check row
    for i in range(len(bo[0])):
        if bo[pos[0]][i] == num and pos[1] != i:
            return False

    # Check column
    for i in range(len(bo)):
        if bo[i][pos[1]] == num and pos[0] != i:
            return False

    # Check box
    box_x = pos[1] // 3
    box_y = pos[0] // 3

    for i in range(box_y*3, box_y*3 + 3):
        for j in range(box_x * 3, box_x*3 + 3):
            if bo[i][j] == num and (i,j) != pos:
                return False

    return True

def find_empty(bo):
    for i in range(len(bo)):
        for j in range(len(bo[0])):
            if bo[i][j] == 0:
                return (i, j)  # row, col
    
    return None

def quit_frame():
    main.destroy()

Square = []
def SquareCreate(): 
    for j in range(0, 9):
        for i in range(0,9):
            data = IntVar()
            t = tk.Entry(main, textvariable=data, justify="center",font=("Arial",16))
            t.place(x=i*40+70, y=j*40+80, width=40, height=40)
            t.delete(0)
            Square.append(data)

def readin():
    listrow0 = []; listrow1 = []; listrow2 = []; listrow3 = []; listrow4 = []; listrow5 = []; listrow6 = []
    listrow7 = []; listrow8 = []
    for i in range(0,9):
        listrow0.append(Square[i].get())
    for i in range(9,18):
        listrow1.append(Square[i].get())
    for i in range(18,27):
        listrow2.append(Square[i].get())
    for i in range(27,36):
        listrow3.append(Square[i].get())
    for i in range(36,45):
        listrow4.append(Square[i].get())
    for i in range(45,54):
        listrow5.append(Square[i].get())
    for i in range(54,63):
        listrow6.append(Square[i].get())
    for i in range(63,72):
        listrow7.append(Square[i].get())
    for i in range(72,81):
        listrow8.append(Square[i].get())
    bo = []
    bo = [listrow0,listrow1,listrow2,listrow3,listrow4,listrow5,listrow6,listrow7,listrow8]
    return bo

bo=readin()

#mainprogramm
main = tk.Tk()
main.geometry("500x540")
main.resizable(width=0, height=0)
l=tk.Label(main, text="Sudoku Bruteforce Solver")
l["font"]="Arial"
l.place(x=150,y=0)
SquareCreate()
button1=tk.Button(main, text="quit", command = quit_frame)
button1.place(x=50,y=450)
button2=tk.Button(main, text="readin", command = readin)
button2.place(x=150,y=450)

solve(bo)

main.mainloop()
Reply
#2
def readin():
    """Assumes solve wants a list"""
    puzzle = []
    for square in Square:
        puzzle.append(square.get())
    return puzzle

def readin():
    """Assumes solve wants a list of rows"""
    puzzle = []
    for r in range(9)
        row = []
        for c in range(9):
            row.append(Square[r*9+c].get()
        puzzle.append(row)
    return puzzle
Reply
#3
Hello deanhystad,

thanks for your answer!!

I added in line 12 to 21 some code for spaces between the entries.

I use the acronym "bo" for "board".

Unfortunately there is an error in line 32, for the expression "bo" it is mentioned "invalid syntax".

I tried very long to find the reason for it but I came to no solution...

What could I do?

Thanks again,

Greetings flash77

import tkinter as tk
from tkinter import Entry, IntVar, Tk

def quit_frame():
    main.destroy()

def SquareCreate(): 
    for j in range(0, 9):
        for i in range(0,9):
            data = IntVar()
            t = tk.Entry(main, textvariable=data, justify="center",font=("Arial",16))
            ixtra=0
            jxtra=0
            if i > 2:
                ixtra=4
            if i > 5:
                ixtra=8
            if j > 2:
                jxtra=4
            if j > 5:
                jxtra=8
            t.place(x=i*40+70+ixtra, y=j*40+80+jxtra, width=40, height=40)
            t.delete(0)
            Square.append(data)

def readin():
    bo = []
    for r in range(9):
        row = []
        for c in range(9):
            row.append(Square[r*9+c].get()
        bo.append(row)    
    return bo 

def solve(bo):
    find = find_empty(bo)
    if not find:
        print("Sudoku solved.")
        return True
    else:
        row, col = find

    for i in range(1,10):
        if valid(bo, i, (row, col)):
            bo[row][col] = i

            if solve(bo):
                return True

            bo[row][col] = 0

    return False

def valid(bo, num, pos):
    # Check row
    for i in range(len(bo[0])):
        if bo[pos[0]][i] == num and pos[1] != i:
            return False

    # Check column
    for i in range(len(bo)):
        if bo[i][pos[1]] == num and pos[0] != i:
            return False

    # Check box
    box_x = pos[1] // 3
    box_y = pos[0] // 3

    for i in range(box_y*3, box_y*3 + 3):
        for j in range(box_x * 3, box_x*3 + 3):
            if bo[i][j] == num and (i,j) != pos:
                return False

    return True

def find_empty(bo):
    for i in range(len(bo)):
        for j in range(len(bo[0])):
            if bo[i][j] == 0:
                return (i, j)  # row, col
    
    return None

#mainprogramm
Square = []
main = tk.Tk()
main.geometry("500x540")
main.resizable(width=0, height=0)
l=tk.Label(main, text="Sudoku Bruteforce Solver")
l["font"]="Arial"
l.place(x=150,y=0)
button1=tk.Button(main, text="quit", command = quit_frame)
button1.place(x=50,y=450)
button2=tk.Button(main, text="readin", command = readin)
button2.place(x=150,y=450)
SquareCreate()
bo=readin()
print(bo)
solve(bo)

main.mainloop()
Reply
#4
Syntax error is in line 31
Reply
#5
Dear deanhystad,

thanks for your patience!

The Squarecreate function creates the entries.

The next steps would be:

When the given values are entered in the entries of the frame, the values shall be read in when the button readin is pressed and the function solve shall be run. When the function solve has solved the puzzle the values of the list board have to be written in the entries.

I have coding experience but I'm a beginner to python so I have to ask again and again...

Please would you be so kind and solve these steps?

Then I would have a working code I could orientate myself...

That would be perhpas a better way instead of asking and asking (and perhaps annoying) again?

Greetings

flash77

import tkinter as tk
from tkinter import Entry, IntVar, Tk

def quit_frame():
    main.destroy()

def SquareCreate(): 
    sq = []
    for j in range(0, 9):
        for i in range(0,9):
            data = IntVar()
            t = tk.Entry(main, textvariable=data, justify="center",font=("Arial",16))
            ixtra=0
            jxtra=0
            if i > 2:
                ixtra=4
            if i > 5:
                ixtra=8
            if j > 2:
                jxtra=4
            if j > 5:
                jxtra=8
            t.place(x=i*40+70+ixtra, y=j*40+80+jxtra, width=40, height=40)
            t.delete(0)
            sq.append(data)
    return sq

def readin(sq):
    bo = []
    for r in range(0,9):
        row = []
        for c in range(0,9):
            row.append(sq[r*9+c].get())
        bo.append(row)    
    return bo 

def solve(bo):
    find = find_empty(bo)
    if not find:
        print("Sudoku solved.")
        return True
    else:
        row, col = find

    for i in range(1,10):
        if valid(bo, i, (row, col)):
            bo[row][col] = i

            if solve(bo):
                return True

            bo[row][col] = 0

    return False

def valid(bo, num, pos):
    # Check row
    for i in range(len(bo[0])):
        if bo[pos[0]][i] == num and pos[1] != i:
            return False

    # Check column
    for i in range(len(bo)):
        if bo[i][pos[1]] == num and pos[0] != i:
            return False

    # Check box
    box_x = pos[1] // 3
    box_y = pos[0] // 3

    for i in range(box_y*3, box_y*3 + 3):
        for j in range(box_x * 3, box_x*3 + 3):
            if bo[i][j] == num and (i,j) != pos:
                return False

    return True

def find_empty(bo):
    for i in range(len(bo)):
        for j in range(len(bo[0])):
            if bo[i][j] == 0:
                return (i, j)  # row, col
    
    return None

#mainprogramm
main = tk.Tk()
main.geometry("500x540")
main.resizable(width=0, height=0)
l=tk.Label(main, text="Sudoku Bruteforce Solver")
l["font"]="Arial"
l.place(x=150,y=0)
button1=tk.Button(main, text="quit", command = quit_frame)
button1.place(x=50,y=450)
button2=tk.Button(main, text="readin", command = readin)
button2.place(x=150,y=450)
SquareCreate()
Square=SquareCreate()
main.mainloop()
Reply
#6
Hello,
I changed the complexity of the example to concentrate on the basics.

The function SquareCreate() generates the squares.

I'm trying to read in the values of the entries with the function readin().

In line 24 it is mentioned that "list index ist out of range".

What I am doing wrong?

I ask politely for help...

Greetings, flash77

import tkinter as tk
from tkinter import Entry, IntVar, Tk

def quit_frame():
    main.destroy()

def SquareCreate(): 
    sq=[]
    for j in range(1,4):
        for i in range(1,4):
            data = IntVar()
            t = tk.Entry(main, textvariable=data, justify="center",font=("Arial",16))
            t.place(x=i*40, y=j*40, width=40, height=40)
            t.delete(0)
            sq.append(data)
    return sq

def readin():
    sq=[]
    bo=[]
    for r in range(1,4):
        row=[]
        for c in range(1,4):
            row.append(sq[r*9+c].get())
        bo.append(row)    
    return bo 
            
#mainprogramm
main = tk.Tk()
main.geometry("500x540")
main.resizable(width=0, height=0)
l=tk.Label(main, text="Sudoku Bruteforce Solver")
l["font"]="Arial"
l.place(x=150,y=0)
button1=tk.Button(main, text="quit", command = quit_frame)
button1.place(x=50,y=450)
button2=tk.Button(main, text="readin", command = readin)
button2.place(x=150,y=450)
SquareCreate()
main.mainloop()
Reply
#7
You don't want to do "sq = []" in readin(). Do you know why that is bad?
Reply
#8
Hello deanhystad,

thanks for your help again...

I'm not sure how to use "sq" in function "readin()". "sq" is a local variable of "squarecreate()".
My attempt to handover
z=squarecreate() to
readin(z)
doesn't work.

If the handover of "sq" to readin would work then "sq=[]" would overwrite it?

So I have to erase "sq=[]" from readin?

Greetings, flash77
Reply
#9
I think you need to take a Python class. There are some really important concepts I don't think you understand, like how variables work and what scope means and how it affects programs. Until you understand that, this sudoku solver is just going to be frustrating.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020