Apr-30-2018, 09:30 PM
Hi all ! I replaced blanks by zeros; tkinter figure always appears. When I type numbers on the figure(clicking "init" first) I should like the puzzle been created. So with that puzzle I run init.py(previous __init__.py) and i have the solution on command prompt.
1. Without tkinter the files are: __main__.py and init.py
2. With tkinter the files are : __main__.py, copy_class.py, SudokuSolver_solver.py, and (the fourth) tkcallasync.py.
Please call the folder: kudoSudoku
Here are the 5 files:
__main__.py
1. Without tkinter the files are: __main__.py and init.py
2. With tkinter the files are : __main__.py, copy_class.py, SudokuSolver_solver.py, and (the fourth) tkcallasync.py.
Please call the folder: kudoSudoku
Here are the 5 files:
__main__.py
""" #SUDOKU WITHOUT TKINTER TO USE WITH init.py from kudoSudoku import sudoku #puzzle = [[0,2,4,0],[1,0,0,3],[4,0,0,2],[0,1,3,0]] puzzle=[[0,0,9,0,0,0,5,6,2],[0,0,0,9,0,0,0,0,0],[2,0,0,0,0,3,1,7,0],[0,0,0,1,9,0,7,8,0],[0,7,5,0,0,0,0,0,0],[0,0,0,2,5,0,6,3,0], [4,0,0,0,0,8,2,9,0],[0,0,0,7,0,0,0,0,0],[0,0,8,0,0,0,3,5,7]] table = sudoku(puzzle) result = table.solve() print(result) """ # __main__.py from multiprocessing import freeze_support#origin if __name__ == '__main__':#origin freeze_support()#origin #import SudokuSolver_class as SudokuSolver#origin import copy_class as SudokuSolver from tkinter import Tk#origin def main():#origin root = Tk()#origin app = SudokuSolver.SudokuSolver(root)#origin root.mainloop()#origin main()#origin2. init.py
#init.py from copy import deepcopy from time import clock class sudoku: def __init__(self,vals): self.__n = len(vals) self.__rows = [] self.__cols = [] self.__eles = [] self.blocks = [] self.isChanged = False self.solved = 0 self.expired = False self.Iterations = 0 self.guesses = 0 for i in range(self.__n): x = subTable(self.__n,self) y = subTable(self.__n,self) z = subTable(self.__n,self) self.__rows.append(x) self.__cols.append(y) self.blocks.append(z) for i in range(self.__n): for j in range(self.__n): k = int((self.__n)**(1/2.0)) b = k*(i//k) + (j//k) e = element(self,self.__rows[i],self.__cols[j],self.blocks[b]) if(vals[i][j] != 0): e.setVal(vals[i][j]) self.__rows[i].setVal(j,e) self.__cols[j].setVal(i,e) self.blocks[b].setVal( k*(i%k) + j%k,e) self.__eles.append(e) for i in self.__eles: for n in range(self.__n): if(i.getVal() == 0): if not (i.myRow().contains(n+1) or i.myCol().contains(n+1) or i.myBlock().contains(n+1)): i.markPoss(n+1) def __markOut(self): for i in self.__rows: i.reposs() for i in self.__cols: i.reposs() for i in self.blocks: i.reposs() def solve(self): clock() self.Iterations += 1 self.isChanged = False self.__markOut() if(self.isChanged): return self.solve() else: if self.expired: #wrong puzzle return { 'done' : False, 'iterations' : self.Iterations, 'guesses' : self.guesses, 'timeTaken' : clock(), 'solution' : None} elif(self.solved == self.__n**2): #solved return { 'done' : True , 'iterations' : self.Iterations, 'guesses' : self.guesses, 'timeTaken' : clock(), 'solution' : self.__myTable() } else: #unsolved return self.__guessOne() def __myTable(self): table = [] for i in self.__rows: row = [] for ele in i.myeles(): if(ele.getVal() == 0): row.append(" ") else: row.append(ele.getVal()) table.append(row) return table def __guessOne(self): self.guesses += 1 selected = 0 itrs = [] for i in range(len(self.__eles)): posses = self.__eles[i].getPoss() if(len(posses) != 0): selected = i itrs = posses break for i in itrs: newTab = deepcopy(self) newTab.__eles[selected].setVal(i) ss = newTab.solve() if(ss['done']): return ss class subTable: def __init__(self,n,table): self.__n = n self.__eles = [None for i in range(n)] self.__vals = [] self.__table = table def setVal(self,i,val): self.__eles[i] = val if(val.getVal() != 0): self.__vals.append(val.getVal()) def myeles(self): return self.__eles def contains(self,val): return val in self.__vals def addVal(self,val): if not val in self.__vals: self.__vals.append(val) for e in self.__eles: if(e != None): e.removePoss(val) def reposs(self): poss = [] for i in self.__eles: if(i.getVal() == 0): poss.append(i.getPoss()) else: poss.append([i.getVal()]) vals = self.solveCons(poss)['val'] for i in range(len(vals)): poss = vals[i] if(len(poss) == 1): if(poss[0] != self.__eles[i].getVal() and self.__eles[i].getVal() != 0): print(self.__eles[i].getVal(),"Errorrr",poss[0]) self.__table.isChanged = True elif(poss[0] != self.__eles[i].getVal() and self.__eles[i].getVal() == 0): self.__eles[i].setVal(poss[0]) self.__table.isChanged = True else: posses = self.__eles[i].getPoss() for poss in posses: if not poss in vals[i]: self.__eles[i].removePoss(poss) self.__table.isChanged = True def solveCons(self,row): if(len(row) == 1): return { "exists" : True , "val" : row} else: head = row[0] tail = row[1:] headfinal = [] tailfinal = [[] for k in range(len(tail))] for ele in head: reformed_tail = list(map(lambda x : [e for e in x if e != ele],tail)) tail_val = self.solveCons(reformed_tail) if(tail_val['exists'] and (not ([] in tail_val['val']))): headfinal.append(ele) tailfinal = concatAll(tailfinal,tail_val['val']) if(len(head) ==0): return {'exists' : False , 'val' : None} else: return {'exists' : True , 'val' : [headfinal] + tailfinal} class element: def __init__(self,table,row,col,block): self.__val = 0 self.__poss = [] self.__row = row self.__col = col self.__block = block self.__table = table def setVal(self,val): if(self.__row.contains(val) or self.__col.contains(val) or self.__block.contains(val)): self.__table.expired = True self.__val = val self.__table.solved += 1 self.clearPoss() self.__block.addVal(val) self.__col.addVal(val) self.__row.addVal(val) def myRow(self): return self.__row def myCol(self): return self.__col def myBlock(self): return self.__block def markPoss(self,val): if not val in self.__poss: self.__poss.append(val) def clearPoss(self): self.__poss = [] def getVal(self): return self.__val def getPoss(self): return self.__poss def removePoss(self,val): if val in self.__poss: self.__poss.remove(val) if(len(self.__poss) == 1 and self.__val == 0): self.setVal(self.__poss[0]) def concatAll(lists1,lists2): lists0 = [] for i in range(len(lists1)): resulting_list = list(lists1[i]) resulting_list.extend([x for x in lists2[i] if x not in lists1[i]]) lists0.append(resulting_list) return lists03. copy_class.py
#copy_class.py import os import SudokuSolver_solver as Solver from random import randint from tkinter import ttk from tkinter import * from tkcallasync import tk_call_async, MULTIPROCESSING #origin #import tkcallasync class SudokuSolver(Frame): sudoku = [[0 for col in range(9)] for row in range(9)] solution = [[0 for col in range(9)] for row in range(9)] exampleSudoku = [[0,0,0,2,1,0,0,0,0], [0,0,7,3,0,0,0,0,0], [0,5,8,0,0,0,0,0,0], [4,3,0,0,0,0,0,0,0], [2,0,0,0,0,0,0,0,8], [0,0,0,0,0,0,0,7,6], [0,0,0,0,0,0,2,5,0], [0,0,0,0,0,7,3,0,0], [0,0,0,0,9,8,0,0,0]] print(sudoku) print(solution) print(exampleSudoku) def __init__(self, parent): Frame.__init__(self, parent, name='frame') self.parent = parent self.initUI() self.blankSUDOKU() self.sudokudir = os.path.join(os.getcwd(), 'sudokus') def initUI(self): self.message_txt = StringVar() self.time_txt = StringVar() self.seconds = 0 self.minutes = 0 self.time_txt.set('0{}:0{}'.format(self.minutes, self.seconds)) self.timer_mode = 'stopped' self.disabled = False self.values = {} self.parent.title('Sudoku Solver') self.pack(fill=BOTH, expand=True) self.message = Label(self, textvariable=self.message_txt) self.message.grid(row=10,column=0,columnspan=8, sticky=E+W) self.timer = Label(self,textvariable=self.time_txt) self.timer.grid(row=10,column=8,sticky=E+W) self.solveBtn = Button(self, text="solve",width=6,command=self.execute_solver) self.solveBtn.grid(row=0,column=0) self.newBtn = Button(self, text="new",width=6,command=self.blankSUDOKU) self.newBtn.grid(row=0,column=1) self.initBtn = Button(self, text="init",width=6,command=self.initSUDOKU) self.initBtn.grid(row=0,column=2) self.startBtn = Button(self, text="start",width=6,command=self.start_timer) self.startBtn.grid(row=0,column=3) self.checkBtn = Button(self, text="check",width=6,command=self.checkSOLUTION) self.checkBtn.grid(row=0,column=6) self.saveBtn = Button(self, text="save",width=6,command=self.saveSUDOKU) self.saveBtn.grid(row=0,column=7) self.printBtn = Button(self, text="print",width=6,command=self.printALL) self.printBtn.grid(row=0,column=8) self.pbar = ttk.Progressbar(self, mode='indeterminate') self.pbar.grid(row=11,column=0, columnspan=9, sticky=W+E) # --- clear all fields and delete all values in sudoku[][] and solution[][] --- # def blankSUDOKU(self): self.message_txt.set('') self.reset_timer() for row in range(9): for col in range(9): self.sudoku[row][col] = ' ' self.solution[row][col] = ' ' self.numEntry = Entry(self, width=5, justify=CENTER, font="Helvetica 12 bold") self.values[row,col] = self.numEntry self.numEntry.grid(row=row+1,column=col, ipady=5) # ----- get a random Sudoku from textfiles ----- # def initSUDOKU(self): self.blankSUDOKU() self.message_txt.set('') self.reset_timer() Files = [] valid = True for filename in os.listdir(self.sudokudir): if filename.startswith('sudoku') and filename.endswith('.txt'): Files.append(filename) L = len(Files) if L < 1: self.message_txt.set('No Sudokus saved, yet! Try this one') self.sudoku = self.copySUDOKU(self.exampleSudoku) else: # ----- fill sudoku array with values from textfile ----- # R = randint(0, L-1) sudokuFile = open(os.path.join(self.sudokudir,Files[R])) row, col = 0, 0 for value in sudokuFile.read(): if value.isdigit() or value==' ': if value=='0': value = ' ' # zeros can also be used as blanks self.sudoku[row][col] = value col += 1 if col==9: if row==8: break row += 1 col = 0 sudokuFile.close() valid = self.checkSUDOKU(self.sudoku)[0] if not valid: self.message_txt.set('%s does not contain a valid sudoku' % Files[R]) else: # ----- make values from random sudoku appear in the GUI ----- # for row in range(9): for col in range(9): value = self.sudoku[row][col] if value!=' ': self.values[row,col].insert(0,value) self.reset_message() def printSUDOKU(self, matrix): for row in range(9): print("|-----------------------------------|") for col in range(9): print("| " + matrix[row][col] + " ",end='') print("|") print("|-----------------------------------|") def printALL(self): print('Sudoku:') self.printSUDOKU(self.sudoku) print('Solution:') self.printSUDOKU(self.solution) def saveSUDOKU(self): CHECK = self.checkSUDOKU(self.solution) if CHECK[0] and CHECK[1]: # check if Sudoku is valid and complete filecount = 1 # variable for how many sudoku files are already existing if not os.path.exists(self.sudokudir): os.makedirs(self.sudokudir) while os.path.isfile(self.path_to("sudoku%s.txt" % filecount)): filecount += 1 sudokuFile = open(self.path_to("sudoku%s.txt" % filecount), 'w') solutionFile = open(self.path_to("solution%s.txt" % filecount), 'w') # ----- create textfiles for sudoku and the solution ----- # for row in range(9): for col in range(9): sudokuFile.write(self.sudoku[row][col]) solutionFile.write(self.solution[row][col]) sudokuFile.write('\n') solutionFile.write('\n') sudokuFile.close() solutionFile.close() self.message_txt.set('Files saved...') else: self.message_txt.set('Sudoku must be valid and complete!') self.reset_message() def copySUDOKU(self, matrix): matrix_copy = [[" " for col in range(9)] for row in range(9)] for row in range(9): for col in range(9): matrix_copy[row][col] = matrix[row][col] return matrix_copy # ----- check if user input makes sense -----# def checkSUDOKU(self, matrix): valid, complete, ctr = True, True, 0 for row in range(9): for col in range(9): value = matrix[row][col] if value!=' ': matrix[row][col]=' ' if not self.consistent(matrix, row, col, value): valid, complete = False, True return valid, complete, row, col matrix[row][col] = value ctr += 1 else: complete = False if ctr<17: valid = False # Sudoku must include at least 17 clues return valid, complete # ----- check if solution is valid ----- # def checkSOLUTION(self): self.getinput(self.solution) CHECK = self.checkSUDOKU(self.solution) if CHECK[0] and CHECK[1]: self.message_txt.set("Solution correct!") elif not CHECK[1]: self.message_txt.set("Sudoku is not complete!") elif not CHECK[0]: self.message_txt.set("Mistake at row %s, col %s" % (CHECK[2], CHECK[3])) self.reset_message() # ----- write user input into values{} ----- # def getinput(self, matrix): for row in range(9): for col in range(9): value = self.values[row,col].get() if value=='': matrix[row][col] = ' ' elif len(value)!=1: matrix[row][col] = ' ' elif not value.isdigit(): matrix[row][col] = ' ' elif int(value)<1 or int(value)>9: matrix[row][col] = ' ' else : matrix[row][col] = value # ----- check if this input leads to a valid solution ----- # def consistent(self, matrix, row, col, value): for i in range(9): if matrix[row][i]==value: return False if matrix[i][col]==value: return False rowStart = row - row%3 colStart = col - col%3 for m in range(3): for k in range(3): if matrix[rowStart+k][colStart+m]==value: return False return True def path_to(self, name): return os.path.join(self.sudokudir, name) def execute_solver(self): self.getinput(self.sudoku) # user input from GUI -> sudoku array if not self.checkSUDOKU(self.sudoku)[0]: # check if user input makes sense self.message_txt.set("This sudoku does not have a solution") self.reset_message() else: if self.disabled: self.message_txt.set("warning, It's still calculating...") self.reset_message() return def callback(result): self.disabled = False status, self.solution, N = result self.pbar.stop() self.printSUDOKU(self.sudoku) self.printSUDOKU(self.solution) self.message_txt.set('Solution found! %s backtracks needed' % N if status else 'No Solution found!') self.fill_solution() self.reset_message(10000) self.disabled = True self.pbar.start(20) tk_call_async(self, Solver.do_solve, args=(self.sudoku), callback=callback, method=MULTIPROCESSING) def fill_solution(self): for row in range(9): for col in range(9): self.values[row,col].delete(0,END) self.values[row,col].insert(0,self.solution[row][col]) def start_timer(self): if self.timer_mode == 'stopped': self.startBtn.configure(text='stop') self.timer_mode = 'running' elif self.timer_mode == 'running': self.startBtn.configure(text='start') self.timer_mode = 'stopped' def timer(): if self.timer_mode == 'stopped': return if self.seconds == 60: self.seconds = 0 self.minutes += 1 if self.seconds > 9 and self.minutes > 9: self.time_txt.set('{}:{}'.format(self.minutes, self.seconds)) elif self.seconds > 9 and self.minutes <= 9: self.time_txt.set('0{}:{}'.format(self.minutes, self.seconds)) elif self.seconds <= 9 and self.minutes <= 9: self.time_txt.set('0{}:0{}'.format(self.minutes, self.seconds)) elif self.seconds <= 9 and self.minutes > 9: self.time_txt.set('{}:0{}'.format(self.minutes, self.seconds)) self.seconds += 1 self.after(1000, timer) timer() def reset_timer(self): self.startBtn.configure(text='start') self.minutes = 0 self.seconds = 0 self.timer_mode = 'stopped' self.time_txt.set('0{}:0{}'.format(self.minutes, self.seconds)) def reset_message(self,DELAY=5000): def reset(): self.message_txt.set('') self.after(DELAY, reset)4.SudokuSolver_solver.py
#SudokuSolver_solver.py BACKTRACK_COUNTER = 0 def do_solve(sudoku): status = wsolve(sudoku) return status, sudoku, BACKTRACK_COUNTER def consistent(matrix, row, col, value): for i in range(9): if matrix[row][i]==value: return False if matrix[i][col]==value: return False rowStart = row - row%3 colStart = col - col%3 for m in range(3): for k in range(3): if matrix[rowStart+k][colStart+m]==value: return False return True class SolutionFound(Exception): pass def wsolve(sudoku): try: solve(sudoku, 0) except SolutionFound: return True except StopSolving: return False return False def solve(sudoku, num): global BACKTRACK_COUNTER BACKTRACK_COUNTER += 1 if num==81: raise SolutionFound return True else: row = int(num / 9) col = num % 9 if sudoku[row][col]!=' ': solve(sudoku, num+1) else: for value in range(1,10): if consistent(sudoku, row, col, str(value)): sudoku[row][col] = str(value) if solve(sudoku, num+1): return True sudoku[row][col]=' ' return False if __name__ == '__main__': printSUDOKU(sudoku) solve(sudoku, 0)5. tkcallasync.py
#tkcallasync.py # Author: Miguel Martinez Lopez # # Uncomment the next line to see my email # print("Author's email: %s"%"61706c69636163696f6e616d656469646140676d61696c2e636f6d".decode("hex")) """ I provide in this module the function "tk_call_async". "tk_call_async" executes the function "computation" asyncronously with the provided "args" and "kwargs" without blocking the tkinter event loop. If "callback" is provided, it will be called with the result when the computation is finnished. If an exception is raised during computation, instead errback will be called. "Polling" will be the frequency to poll to check for results. There is two methods to execute the task: using multiprocessing or using threads. """ import traceback import threading # Python 3 support try: from Queue import Queue except ImportError: from queue import Queue MULTIPROCESSING = 0 THREADS = 1 def tk_call_async(window, computation, args=(), kwargs={}, callback=None, errback=None, polling=500, method=MULTIPROCESSING): if method == MULTIPROCESSING: # I use threads because on windows creating a new python process freezes a little the event loop. future_result= Queue() worker = threading.Thread(target=_request_result_using_multiprocessing, args=(computation, args, kwargs, future_result)) worker.daemon = True worker.start() elif method == THREADS: future_result = _request_result_using_threads(computation, args=args, kwargs=kwargs) else: raise ValueError("Not valid method") if callback is not None or errback is not None: _after_completion(window, future_result, callback, errback, polling) return future_result def _request_result_using_multiprocessing(func, args, kwargs, future_result): import multiprocessing queue= multiprocessing.Queue() worker = multiprocessing.Process(target=_compute_result, args=(func, args, kwargs, queue)) worker.daemon = True worker.start() return future_result.put(queue.get()) def _request_result_using_threads(func, args, kwargs): future_result= Queue() worker = threading.Thread(target=_compute_result, args=(func, args, kwargs, future_result)) worker.daemon = True worker.start() return future_result def _after_completion(window, future_result, callback, errback, polling): def check(): try: result = future_result.get(block=False) except: window.after(polling, check) else: if isinstance(result, Exception): if errback is not None: errback(result) else: if callback is not None: callback(result) window.after(0, check) def _compute_result(func, func_args, func_kwargs, future_result): try: _result = func(*func_args, **func_kwargs) except Exception as errmsg: _result = Exception(traceback.format_exc()) future_result.put(_result) # Multiprocessing uses pickle on windows. # A pickable function should be in top module or imported from another module. # This is requirement is not mandatory on Linux because python uses behind the scenes the fork operating system call. # But on Windows it uses named pipes and pickle. def _example_calculation(n): if n == 0: return 0 elif n == 1: return 1 else: return _example_calculation(n-1)+_example_calculation(n-2) if __name__ == "__main__": try: from Tkinter import Tk, Frame, Entry, Label, Button, IntVar, StringVar, LEFT import tkMessageBox as messagebox except ImportError: from tkinter import Tk, Frame, Entry, Label, Button, IntVar, StringVar, LEFT from tkinter import messagebox disabled = False def calculate_fibonacci(): global disabled if disabled: messagebox.showinfo("warning", "It's still calculating...") return def callback(result): global disabled disabled = False result_var.set(result) disabled = True tk_call_async(root, _example_calculation, args=(n.get(),), callback=callback, method =MULTIPROCESSING) root = Tk() n = IntVar(value=35) row = Frame(root) row.pack() Entry(row, textvariable=n).pack(side=LEFT) Button(row, text="Calculate fibonnaci", command =calculate_fibonacci).pack(side=LEFT) Button(row, text="It's responsive", command= lambda: messagebox.showinfo("info", "it's responsive")).pack(side=LEFT) result_var = StringVar() Label(root, textvariable=result_var).pack()