def import_grille(self, fichier=None): """ importe une grille stockée dans un fichier txt sous forme de chiffres séparés par des espaces (0 = case vide) """ if self.chrono_on: self.play_pause() rep = _("Yes") if self.debut: rep = two_button_box(self, _("Confirmation"), _("Do you want to abandon the current puzzle?"), _("Yes"), _("No"), self.im_question) if rep == _("Yes"): if not fichier: fichier = askopenfilename(initialdir=cst.INITIALDIR, defaultextension='.txt', filetypes=[('Text', '*.txt'), ('Tous les fichiers', "*")]) if fichier: try: self.load_grille(fichier) except (ValueError, UnicodeDecodeError): one_button_box(self, _("Error"), _("The file does not have the right format. It should be a .txt file with cell values separated by one space. 0 means empty cell."), image=self.im_erreur) except FileNotFoundError: one_button_box(self, _("Error"), _("The file %(file)r does not exist.") % fichier, image=self.im_erreur) elif self.debut: self.play_pause()
def resolution_init(self): """ Résolution de la grille initiale (sans tenir compte des valeurs rentrées par l'utilisateur. """ grille = Grille() for i in range(9): for j in range(9): if not self.blocs[i, j].is_modifiable(): val = self.blocs[i, j].get_val() grille.ajoute_init(i, j, val) self.configure(cursor="watch") self.update() sol = grille.solve() self.configure(cursor="") if type(sol) == np.ndarray: for i in range(9): for j in range(9): val = self.blocs[i, j].get_val() if not val: self.blocs[i, j].edit_chiffre(sol[i, j]) self.blocs[i, j].affiche_solution() elif self.blocs[i, j].is_modifiable(): if val != sol[i, j]: self.blocs[i, j].edit_chiffre(sol[i, j]) self.blocs[i, j].affiche_erreur() self.restart() self.nb_cases_remplies = 81 elif sol[1]: i, j = sol[1] if self.blocs[i, j].get_val(): self.blocs[i, j].affiche_erreur() one_button_box(self, _("Error"), _("The grid is wrong. It cannot be solved."), image=self.im_erreur) else: one_button_box(self, _("Error"), _("Resolution failed."), image=self.im_erreur)
def import_partie(self): """ importe une partie stockée dans un fichier .sudoku """ if self.chrono_on: self.play_pause() rep = _("Yes") if self.debut: rep = two_button_box(self, _("Confirmation"), _("Do you want to abandon the current puzzle?"), _("Yes"), _("No"), self.im_question) if rep == _("Yes"): fichier = askopenfilename(initialdir=cst.INITIALDIR, defaultextension='.sudoku', filetypes=[('Sudoku', '*.sudoku')]) if fichier: try: self.load_sudoku(fichier) except FileNotFoundError: one_button_box(self, _("Error"), _("The file %(file)r does not exist.") % fichier, image=self.im_erreur) except (KeyError, EOFError, UnpicklingError): one_button_box(self, _("Error"), _("This file is not a valid sudoku file."), image=self.im_erreur) elif self.debut: self.play_pause()
def test_remplie(self): """ Test si la grille est remplie """ if self.nb_cases_remplies == 81: grille = Grille() for i in range(9): for j in range(9): val = self.blocs[i, j].get_val() if val: grille.ajoute_init(i, j, val) sol = grille.solve() if type(sol) == np.ndarray: self.play_pause() self.frame_pause.place_forget() one_button_box(self, _("Information"), _("You solved the puzzle in %(min)i minutes and %(sec)i secondes.") % {"min": self.chrono[0], "sec": self.chrono[1]}, image=self.im_info) if self.level != "unknown": best = CONFIG.get("Statistics", self.level) current = self.chrono[0] * 60 + self.chrono[1] if best: best = int(best) if current < best: CONFIG.set("Statistics", self.level, str(current)) else: CONFIG.set("Statistics", self.level, str(current)) self.b_pause.configure(state="disabled") self.debut = False else: i, j = sol[1] if self.blocs[i, j].get_val(): self.blocs[i, j].affiche_erreur() one_button_box(self, _("Information"), _("There is a mistake."), image=self.im_info)
def load_grille(self, file): gr = np.loadtxt(file, dtype=int) if gr.shape == (9, 9): self.affiche_grille(gr) self.level = "unknown" else: one_button_box(self, _("Error"), _("This is not a 9x9 sudoku grid."), image=self.im_erreur)
def resolution(self): if self.chrono_on: self.play_pause() rep = two_button_box(self, _("Confirmation"), _("Do you really want to get the solution?"), _("Yes"), _("No"), image=self.im_question) if rep == _("Yes"): self.frame_pause.place_forget() grille = Grille() for i in range(9): for j in range(9): val = self.blocs[i, j].get_val() if val: grille.ajoute_init(i, j, val) self.configure(cursor="watch") self.update() sol = grille.solve() self.configure(cursor="") if type(sol) == np.ndarray: for i in range(9): for j in range(9): val = self.blocs[i, j].get_val() if not val: self.blocs[i, j].edit_chiffre(sol[i, j]) self.blocs[i, j].affiche_solution() self.restart() self.b_restart.configure(state="normal") self.nb_cases_remplies = 81 elif sol[1]: i, j = sol[1] if self.blocs[i, j].get_val(): self.blocs[i, j].affiche_erreur() i, j = 0, 0 while i < 9 and self.blocs[i, j].is_modifiable(): j += 1 if j == 9: i += 1 j = 0 if i < 9: # il y a au moins une case de type "initial" rep = two_button_box(self, _("Error"), _("The grid is wrong. It cannot be solved. Do you want the solution of the initial grid?"), _("Yes"), _("No"), image=self.im_erreur) if rep == _("Yes"): self.resolution_init() else: one_button_box(self, _("Error"), _("The grid is wrong. It cannot be solved."), image=self.im_erreur) else: one_button_box(self, _("Error"), _("Resolution failed."), image=self.im_erreur)
def __init__(self, file=None): Tk.__init__(self, className="Sudoku-Tk") self.title("Sudoku-Tk") self.resizable(0, 0) self.protocol("WM_DELETE_WINDOW", self.quitter) cst.set_icon(self) self.columnconfigure(3, weight=1) # --- style bg = '#dddddd' activebg = '#efefef' pressedbg = '#c1c1c1' lightcolor = '#ededed' darkcolor = '#cfcdc8' bordercolor = '#888888' focusbordercolor = '#5E5E5E' disabledfg = '#999999' disabledbg = bg button_style_config = {'bordercolor': bordercolor, 'background': bg, 'lightcolor': lightcolor, 'darkcolor': darkcolor} button_style_map = {'background': [('active', activebg), ('disabled', disabledbg), ('pressed', pressedbg)], 'lightcolor': [('pressed', darkcolor)], 'darkcolor': [('pressed', lightcolor)], 'bordercolor': [('focus', focusbordercolor)], 'foreground': [('disabled', disabledfg)]} style = Style(self) style.theme_use(cst.STYLE) style.configure('TFrame', background=bg) style.configure('TLabel', background=bg) style.configure('TScrollbar', gripcount=0, troughcolor=pressedbg, **button_style_config) style.map('TScrollbar', **button_style_map) style.configure('TButton', **button_style_config) style.map('TButton', **button_style_map) style.configure('TCheckutton', **button_style_config) style.map('TCheckutton', **button_style_map) self.option_add('*Toplevel.background', bg) self.option_add('*Menu.background', bg) self.option_add('*Menu.activeBackground', activebg) self.option_add('*Menu.activeForeground', "black") self.configure(bg=bg) style.configure("bg.TFrame", background="grey") style.configure("case.TFrame", background="white") style.configure("case.TLabel", background="white", foreground="black") style.configure("case_init.TFrame", background="lightgrey") style.configure("case_init.TLabel", background="lightgrey", foreground="black") style.configure("erreur.TFrame", background="white") style.configure("erreur.TLabel", background="white", foreground="red") style.configure("solution.TFrame", background="white") style.configure("solution.TLabel", background="white", foreground="blue") style.configure("pause.TLabel", foreground="grey", background='white') # --- images self.im_erreur = open_image(cst.ERREUR) self.im_pause = open_image(cst.PAUSE) self.im_restart = open_image(cst.RESTART) self.im_play = open_image(cst.PLAY) self.im_info = open_image(cst.INFO) self.im_undo = open_image(cst.UNDO) self.im_redo = open_image(cst.REDO) self.im_question = open_image(cst.QUESTION) # --- timer self.chrono = [0, 0] self.tps = Label(self, text=" %02i:%02i" % tuple(self.chrono), font="Arial 16") self.debut = False # la partie a-t-elle commencée ? self.chrono_on = False # le chrono est-il en marche ? # --- buttons self.b_pause = Button(self, state="disabled", image=self.im_pause, command=self.play_pause) self.b_restart = Button(self, state="disabled", image=self.im_restart, command=self.recommence) self.b_undo = Button(self, image=self.im_undo, command=self.undo) self.b_redo = Button(self, image=self.im_redo, command=self.redo) # --- tooltips self.tooltip_wrapper = TooltipWrapper(self) self.tooltip_wrapper.add_tooltip(self.b_pause, _("Pause game")) self.tooltip_wrapper.add_tooltip(self.b_restart, _("Restart game")) self.tooltip_wrapper.add_tooltip(self.b_undo, _("Undo")) self.tooltip_wrapper.add_tooltip(self.b_redo, _("Redo")) # --- numbers frame_nb = Frame(self, style='bg.TFrame', width=36) self.progression = [] for i in range(1, 10): self.progression.append(Progression(frame_nb, i)) self.progression[-1].pack(padx=1, pady=1) # --- level indication frame = Frame(self) frame.grid(row=0, columnspan=5, padx=(30, 10), pady=10) Label(frame, text=_("Level") + ' - ', font="Arial 16").pack(side='left') self.label_level = Label(frame, font="Arial 16", text=_("Unknown")) self.label_level.pack(side='left') self.level = "unknown" # puzzle level # --- frame contenant la grille de sudoku self.frame_puzzle = Frame(self, style="bg.TFrame") self.frame_pause = Frame(self, style="case.TFrame") self.frame_pause.grid_propagate(False) self.frame_pause.columnconfigure(0, weight=1) self.frame_pause.rowconfigure(0, weight=1) Label(self.frame_pause, text='PAUSE', style='pause.TLabel', font='Arial 30 bold').grid() # --- placement frame_nb.grid(row=1, column=6, sticky='en', pady=0, padx=(0, 30)) self.frame_puzzle.grid(row=1, columnspan=5, padx=(30, 15)) self.tps.grid(row=2, column=0, sticky="e", padx=(30, 10), pady=30) self.b_pause.grid(row=2, column=1, sticky="w", padx=2, pady=30) self.b_restart.grid(row=2, column=2, sticky="w", padx=2, pady=30) self.b_undo.grid(row=2, column=3, sticky="e", pady=30, padx=2) self.b_redo.grid(row=2, column=4, sticky="w", pady=30, padx=(2, 10)) # --- menu menu = Menu(self, tearoff=0) menu_nouveau = Menu(menu, tearoff=0) menu_levels = Menu(menu_nouveau, tearoff=0) menu_levels.add_command(label=_("Easy"), command=self.new_easy) menu_levels.add_command(label=_("Medium"), command=self.new_medium) menu_levels.add_command(label=_("Difficult"), command=self.new_difficult) menu_nouveau.add_cascade(label=_("Level"), menu=menu_levels) menu_nouveau.add_command(label=_("Generate a puzzle"), command=self.genere_grille, accelerator="Ctrl+G") menu_nouveau.add_command(label=_("Empty grid"), command=self.grille_vide, accelerator="Ctrl+N") menu_ouvrir = Menu(menu, tearoff=0) menu_ouvrir.add_command(label=_("Game"), command=self.import_partie, accelerator="Ctrl+O") menu_ouvrir.add_command(label=_("Puzzle"), command=self.import_grille, accelerator="Ctrl+Shift+O") menu_game = Menu(menu, tearoff=0) menu_game.add_command(label=_("Restart"), command=self.recommence) menu_game.add_command(label=_("Solve"), command=self.resolution) menu_game.add_command(label=_("Save"), command=self.sauvegarde, accelerator="Ctrl+S") menu_game.add_command(label=_("Export"), command=self.export_impression, accelerator="Ctrl+E") menu_game.add_command(label=_("Evaluate level"), command=self.evaluate_level) menu_language = Menu(menu, tearoff=0) self.langue = StringVar(self) self.langue.set(cst.LANGUE[:2]) menu_language.add_radiobutton(label="Français", variable=self.langue, value="fr", command=self.translate) menu_language.add_radiobutton(label="English", variable=self.langue, value="en", command=self.translate) menu_help = Menu(menu, tearoff=0) menu_help.add_command(label=_("Help"), command=self.aide, accelerator='F1') menu_help.add_command(label=_("About"), command=self.about) menu.add_cascade(label=_("New"), menu=menu_nouveau) menu.add_cascade(label=_("Open"), menu=menu_ouvrir) menu.add_cascade(label=_("Game"), menu=menu_game) menu.add_cascade(label=_("Language"), menu=menu_language) menu.add_command(label=_("Statistics"), command=self.show_stat) menu.add_cascade(label=_("Help"), menu=menu_help) self.configure(menu=menu) # --- clavier popup self.clavier = None # --- cases self.nb_cases_remplies = 0 self.blocs = np.zeros((9, 9), dtype=object) for i in range(9): for j in range(9): self.blocs[i, j] = Case(self.frame_puzzle, i, j, self.update_nbs, width=50, height=50) px, py = 1, 1 if i % 3 == 2 and i != 8: py = (1, 3) if j % 3 == 2 and j != 8: px = (1, 3) self.blocs[i, j].grid(row=i, column=j, padx=px, pady=py) self.blocs[i, j].grid_propagate(0) # --- undo/redo stacks self._undo_stack = [] self._redo_stack = [] # --- raccourcis clavier et actions de la souris self.bind("<Button>", self.edit_case) self.bind("<Control-z>", lambda e: self.undo()) self.bind("<Control-y>", lambda e: self.redo()) self.bind("<Control-s>", lambda e: self.sauvegarde()) self.bind("<Control-e>", lambda e: self.export_impression()) self.bind("<Control-o>", lambda e: self.import_partie()) self.bind("<Control-Shift-O>", lambda e: self.import_grille()) self.bind("<Control-n>", lambda e: self.grille_vide()) self.bind("<Control-g>", lambda e: self.genere_grille()) self.bind("<FocusOut>", self.focus_out) self.bind("<F1>", self.aide) # --- open game if file: try: self.load_sudoku(file) except FileNotFoundError: one_button_box(self, _("Error"), _("The file %(file)r does not exist.") % file, image=self.im_erreur) except (KeyError, EOFError, UnpicklingError): try: self.load_grille(file) except Exception: one_button_box(self, _("Error"), _("This file is not a valid sudoku file."), image=self.im_erreur) elif exists(cst.PATH_SAVE): self.load_sudoku(cst.PATH_SAVE) remove(cst.PATH_SAVE)
def translate(self): """ changement de la langue de l'interface """ one_button_box(self, _("Information"), _("The language setting will take effect after restarting the application"), image=self.im_info) CONFIG.set("General", "language", self.langue.get())