init
BIN
assets/brain.png
Executable file
After Width: | Height: | Size: 5.6 KiB |
BIN
assets/cross.png
Executable file
After Width: | Height: | Size: 5.1 KiB |
BIN
assets/down_left.png
Executable file
After Width: | Height: | Size: 4.7 KiB |
BIN
assets/down_right.png
Executable file
After Width: | Height: | Size: 4.7 KiB |
BIN
assets/empty.png
Executable file
After Width: | Height: | Size: 4.5 KiB |
BIN
assets/end.png
Executable file
After Width: | Height: | Size: 4.7 KiB |
BIN
assets/end_down.png
Executable file
After Width: | Height: | Size: 5 KiB |
BIN
assets/end_left.png
Executable file
After Width: | Height: | Size: 4.9 KiB |
BIN
assets/end_right.png
Executable file
After Width: | Height: | Size: 4.9 KiB |
BIN
assets/end_up.png
Executable file
After Width: | Height: | Size: 5 KiB |
BIN
assets/logo.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
assets/return.png
Executable file
After Width: | Height: | Size: 4.8 KiB |
BIN
assets/save.png
Executable file
After Width: | Height: | Size: 404 B |
BIN
assets/start.png
Executable file
After Width: | Height: | Size: 4.7 KiB |
BIN
assets/straight.png
Executable file
After Width: | Height: | Size: 4.6 KiB |
BIN
assets/straight_down.png
Executable file
After Width: | Height: | Size: 4.8 KiB |
BIN
assets/three_down.png
Executable file
After Width: | Height: | Size: 4.9 KiB |
BIN
assets/three_left.png
Executable file
After Width: | Height: | Size: 4.9 KiB |
BIN
assets/three_right.png
Executable file
After Width: | Height: | Size: 4.9 KiB |
BIN
assets/three_up.png
Executable file
After Width: | Height: | Size: 4.9 KiB |
BIN
assets/up_left.png
Executable file
After Width: | Height: | Size: 4.7 KiB |
BIN
assets/up_right.png
Executable file
After Width: | Height: | Size: 4.7 KiB |
BIN
example.png
Executable file
After Width: | Height: | Size: 126 KiB |
BIN
lib/3uBkb7p-666847106.png
Executable file
After Width: | Height: | Size: 511 KiB |
74
lib/maze.py
Executable file
|
@ -0,0 +1,74 @@
|
|||
from random import shuffle, randint, choice
|
||||
from lib.pile import *
|
||||
|
||||
|
||||
def creation(x: int, y: int) -> list:
|
||||
"""
|
||||
Renvoie une liste de listes qui servent de création au labyrinthe.
|
||||
In x, y: int
|
||||
Out tab: list
|
||||
"""
|
||||
if x % 2 == 0:
|
||||
x += 1
|
||||
if y % 2 == 0:
|
||||
y += 1
|
||||
|
||||
tab = [
|
||||
["?" if i % 2 != 0 and j % 2 != 0 else "#" for j in range(y)] for i in range(x)
|
||||
]
|
||||
|
||||
entrance_exit = choice(["horizontal", "vertical"])
|
||||
|
||||
if entrance_exit == "horizontal":
|
||||
entry_point = (2 * randint(1, x // 2) - 1, 0)
|
||||
exit_point = (2 * randint(1, x // 2) - 1, y - 1)
|
||||
else:
|
||||
entry_point = (0, 2 * randint(1, y // 2 - 1) - 1)
|
||||
exit_point = (x - 1, 2 * randint(1, y // 2 - 1) - 1)
|
||||
|
||||
tab[entry_point[0]][entry_point[1]] = ">"
|
||||
tab[exit_point[0]][exit_point[1]] = "O"
|
||||
|
||||
return tab
|
||||
|
||||
|
||||
def gen_maze(sizex: int, sizey: int, lab=None, cells=None, x=None, y=None) -> list:
|
||||
"""
|
||||
Cree un labyrinthe avec un algorithme de recherche en profondeur (depth-first search).
|
||||
Entree x, y, lab cells: int, int, list, Pile
|
||||
Sortie lab: list
|
||||
"""
|
||||
if cells is None:
|
||||
lab = creation(sizey, sizex)
|
||||
valid_positions = [
|
||||
(x, y)
|
||||
for y in range(1, sizey - 2)
|
||||
for x in range(1, sizex - 2)
|
||||
if lab[y][x] != "#"
|
||||
]
|
||||
pos = randint(0, len(valid_positions) // 2 - 1) * 2
|
||||
x, y = valid_positions[pos]
|
||||
cells = Pile()
|
||||
lab[y][x] = " "
|
||||
cells.empiler((x, y))
|
||||
|
||||
while len(cells) > 0:
|
||||
suiv = []
|
||||
for coo in [(x - 2, y), (x + 2, y), (x, y - 2), (x, y + 2)]:
|
||||
if 0 < coo[0] and 0 <= coo[1]:
|
||||
if coo[0] < sizex and coo[1] < sizey:
|
||||
if lab[coo[1]][coo[0]] == "?":
|
||||
suiv.append(coo)
|
||||
|
||||
if suiv != []:
|
||||
shuffle(suiv)
|
||||
diff = ((suiv[0][0] - x) // 2, (suiv[0][1] - y) // 2)
|
||||
x, y = suiv[0][0], suiv[0][1]
|
||||
lab[y - diff[1]][x - diff[0]] = " "
|
||||
lab[y][x] = " "
|
||||
cells.empiler((x, y))
|
||||
else:
|
||||
coo = cells.depiler()
|
||||
x, y = coo[0], coo[1]
|
||||
|
||||
return lab
|
70
lib/pile.py
Executable file
|
@ -0,0 +1,70 @@
|
|||
class Cellule:
|
||||
def __init__(self, x):
|
||||
"""Constructeur de la classe Cellule :
|
||||
valeur contient la valeur stockee dans la cellule.
|
||||
suivant contient le pointeur vers la cellule suivante.
|
||||
suivant est toujours initialise a None."""
|
||||
self.valeur = x
|
||||
self.suivant = None
|
||||
|
||||
def __del__(self):
|
||||
"""Destructeur de la classe Cellule :
|
||||
Supprime la valeur, le pointeur suivant et la cellule elle-meme."""
|
||||
del self.valeur
|
||||
del self.suivant
|
||||
del self
|
||||
|
||||
|
||||
class Pile:
|
||||
def __init__(self):
|
||||
"""Constructeur de la classe Pile :
|
||||
sommet contient le pointeur vers la cellule suivante.
|
||||
sommet est toujours initialise a None."""
|
||||
self.sommet = None
|
||||
self.__taille = 0
|
||||
|
||||
def est_vide(self):
|
||||
"""Renvoie True si la pile est vide, False sinon.
|
||||
Entree : aucune.
|
||||
Sortie : booleen."""
|
||||
return self.__taille == 0
|
||||
|
||||
def __len__(self):
|
||||
"""Renvoie la taille de la pile.
|
||||
Entree : aucune.
|
||||
Sortie : entier positif."""
|
||||
return self.__taille
|
||||
|
||||
def empiler(self, x):
|
||||
"""Ajoute x en tete de pile.
|
||||
On cree une instance de cellule avec la valeur x
|
||||
et suivant pointe vers la tete.
|
||||
Entree : x est une valeur possible.
|
||||
Sortie : aucune."""
|
||||
self.__taille += 1 # la taille augmente de 1
|
||||
if self.est_vide():
|
||||
self.sommet = Cellule(x)
|
||||
else:
|
||||
nouveau_sommet = Cellule(x)
|
||||
nouveau_sommet.suivant = (
|
||||
self.sommet
|
||||
) # on relie la Cellule a la suite de la Pile
|
||||
self.sommet = (
|
||||
nouveau_sommet # le sommet de la pile devient la nouvelle Cellule
|
||||
)
|
||||
return None
|
||||
|
||||
def depiler(self):
|
||||
"""Supprimer la Cellule de sommet et renvoie sa valeur.
|
||||
Entree : aucune.
|
||||
Sortie : aucune."""
|
||||
if self.est_vide():
|
||||
raise BrokenPipeError("La Pile est vide !")
|
||||
cellule_a_depiler = self.sommet
|
||||
self.sommet = (
|
||||
cellule_a_depiler.suivant
|
||||
) # on court-circuite la Cellule de sommet
|
||||
retour = cellule_a_depiler.valeur # on recupere sa valeur
|
||||
del cellule_a_depiler # on la supprime
|
||||
self.__taille -= 1 # on met a jour la taille de la pile
|
||||
return retour
|
235
lib/resolv.py
Executable file
|
@ -0,0 +1,235 @@
|
|||
from lib.maze import gen_maze
|
||||
from lib.pile import Pile
|
||||
from random import shuffle
|
||||
from tkinter import Canvas, Tk, Button
|
||||
import tkinter.messagebox
|
||||
from time import time
|
||||
|
||||
|
||||
def find_maze_start(maze: list) -> tuple:
|
||||
"""
|
||||
Find the coo of the maze's entrance.
|
||||
In maze: list
|
||||
Out: tuple
|
||||
"""
|
||||
maze_end, mazex = len(maze), len(maze[0])
|
||||
for i in range(maze_end):
|
||||
for l in range(mazex):
|
||||
if maze[i][l] == ">":
|
||||
return (l, i)
|
||||
|
||||
# si le labyrinthe n'a pas d'entree
|
||||
tkinter.messagebox.showinfo(
|
||||
title="Amaze!", message="Il y a des erreurs dans le labyrinthe!"
|
||||
)
|
||||
raise Exception("Il y a des erreurs dans le labyrinthe!")
|
||||
return (-1, -1)
|
||||
|
||||
|
||||
def find_available_moves(
|
||||
curr_x: int, curr_y: int, sizex: int, sizey: int, maze: list
|
||||
) -> list:
|
||||
"""
|
||||
renvoit les coordonnees possible pour certain x et y
|
||||
In curr_x, curry, sizex, sizey, maze: int, int, int, int, list
|
||||
Out: list
|
||||
"""
|
||||
moves = [
|
||||
(curr_x - 1, curr_y),
|
||||
(curr_x + 1, curr_y),
|
||||
(curr_x, curr_y - 1),
|
||||
(curr_x, curr_y + 1),
|
||||
]
|
||||
return [
|
||||
(x, y)
|
||||
for x, y in moves
|
||||
if 0 < x < sizex and 0 < y < sizey and maze[y][x] in [" ", "O"]
|
||||
]
|
||||
|
||||
|
||||
def rectangle(
|
||||
x: int, y: int, taille_cells: int, couleur: str, canvas: Canvas, *, cailloux=None
|
||||
) -> Pile:
|
||||
"""
|
||||
cree un carre au coordonnees x et y
|
||||
In x, y, taille_cells, couleur, canvas, cailloux = int, int, int, str, Canvas(), Pile()
|
||||
Out cailloux: Pile()
|
||||
"""
|
||||
if cailloux == None:
|
||||
canvas.create_rectangle(
|
||||
(x * taille_cells) - taille_cells / 2,
|
||||
(y * taille_cells) - taille_cells / 2,
|
||||
((x + 1) * taille_cells) - taille_cells / 2,
|
||||
((y + 1) * taille_cells) - taille_cells / 2,
|
||||
width=0,
|
||||
fill=couleur,
|
||||
tags=("path",),
|
||||
)
|
||||
else:
|
||||
cailloux.empiler(
|
||||
canvas.create_rectangle(
|
||||
(x * taille_cells) - taille_cells / 2,
|
||||
(y * taille_cells) - taille_cells / 2,
|
||||
((x + 1) * taille_cells) - taille_cells / 2,
|
||||
((y + 1) * taille_cells) - taille_cells / 2,
|
||||
width=0,
|
||||
fill=couleur,
|
||||
tags=("path",),
|
||||
)
|
||||
)
|
||||
return cailloux
|
||||
|
||||
|
||||
def win(
|
||||
x: int, y: int, taille_cells: int, start: int, canvas: Canvas, button: Button
|
||||
) -> None:
|
||||
"""
|
||||
gere la fin du programme, quand la tete trouve la fin du labyrinthe.
|
||||
In x, y, taille_cells, start, canvas, button: int, int, int, int, Canva(), Button()
|
||||
Out: None
|
||||
"""
|
||||
# reactive le bouton de resolution
|
||||
button["state"] = "active"
|
||||
|
||||
# affiche un carre vert sur la fin du labyrinthe
|
||||
rectangle(x, y, taille_cells, "green", canvas)
|
||||
|
||||
# calcule le temps
|
||||
end = time()
|
||||
seconds = round(end) - round(start)
|
||||
heures, minutes = 0, 0
|
||||
while seconds > 59:
|
||||
minutes += 1
|
||||
seconds -= 60
|
||||
if minutes > 59:
|
||||
heures += 1
|
||||
minutes -= 60
|
||||
if minutes > 0:
|
||||
m = f"{minutes}min "
|
||||
else:
|
||||
m = ""
|
||||
if heures > 0:
|
||||
h = f"{heures}h "
|
||||
else:
|
||||
h = ""
|
||||
|
||||
# affiche le temps
|
||||
tkinter.messagebox.showinfo(
|
||||
title="Amaze!", message=f"Labyrinthe résolu en {h}{m}{seconds}s!"
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def delete_old_path(canvas: Canvas) -> None:
|
||||
"""
|
||||
reset l'ancien chemin.
|
||||
In: canvas: Canvas()
|
||||
Out: None
|
||||
"""
|
||||
items = canvas.find_all()
|
||||
|
||||
for item_id in items:
|
||||
tags = canvas.gettags(item_id)
|
||||
if "path" in tags:
|
||||
canvas.delete(item_id)
|
||||
return None
|
||||
|
||||
|
||||
def resolve(
|
||||
maze: list,
|
||||
canvas: Canvas,
|
||||
root: Tk,
|
||||
taille_cells: int,
|
||||
*,
|
||||
button=None,
|
||||
poucet=None,
|
||||
x=None,
|
||||
y=None,
|
||||
cailloux=None,
|
||||
start=None,
|
||||
) -> None:
|
||||
"""
|
||||
Resout le labyrinthe, compte le temps de resolution et grise le bouton de resolution
|
||||
In :
|
||||
maze (list)
|
||||
canvas (Canvas())
|
||||
root (Tk())
|
||||
taille_cells(int)
|
||||
button (Button())
|
||||
poucet (Pile())
|
||||
x (int)
|
||||
y (int)
|
||||
cailloux (Pile())
|
||||
start (int)
|
||||
Out :
|
||||
None
|
||||
"""
|
||||
if poucet != None and poucet.est_vide():
|
||||
try:
|
||||
find_available_moves(x, y, maze) == []
|
||||
except:
|
||||
button["state"] = "active"
|
||||
tkinter.messagebox.showinfo(
|
||||
title="Amaze!", message=f"Labyrinthe impossible!"
|
||||
)
|
||||
del poucet, cailloux, x, y, start, maze
|
||||
return None
|
||||
|
||||
if poucet == None: # initialisation
|
||||
delete_old_path(canvas)
|
||||
button["state"] = "disabled"
|
||||
start = time()
|
||||
x, y = find_maze_start(maze)
|
||||
rectangle(x, y, taille_cells, "black", canvas)
|
||||
sizex, sizey = len(maze[0]), len(maze)
|
||||
poucet = Pile()
|
||||
cailloux = Pile()
|
||||
|
||||
sizex, sizey = len(maze[0]), len(maze)
|
||||
suiv = find_available_moves(x, y, sizex, sizey, maze)
|
||||
|
||||
if suiv != []: # si on peut avancer
|
||||
shuffle(suiv)
|
||||
x, y = suiv[0][0], suiv[0][1]
|
||||
|
||||
if maze[y][x] == "O":
|
||||
win(x, y, taille_cells, start, canvas, button)
|
||||
del poucet, cailloux, x, y, start, maze
|
||||
return None
|
||||
|
||||
maze[y][x] = "V"
|
||||
poucet.empiler((x, y))
|
||||
cailloux = rectangle(x, y, taille_cells, "red", canvas, cailloux=cailloux)
|
||||
|
||||
else: # sinon on recule
|
||||
coo = poucet.depiler()
|
||||
x, y = coo[0], coo[1]
|
||||
|
||||
next_suiv = find_available_moves(x, y, sizex, sizey, maze)
|
||||
for x2, y2 in next_suiv:
|
||||
if maze[y][x] == "O":
|
||||
win(x, y, taille_cells, end, canvas, button)
|
||||
del poucet, cailloux, x, y, start, maze
|
||||
return None
|
||||
if next_suiv == []:
|
||||
edit = cailloux.depiler()
|
||||
canvas.itemconfig(edit, fill="#a6a6a6")
|
||||
else:
|
||||
poucet.empiler((x, y))
|
||||
|
||||
root.after(
|
||||
5,
|
||||
lambda: resolve(
|
||||
maze,
|
||||
canvas,
|
||||
root,
|
||||
taille_cells,
|
||||
poucet=poucet,
|
||||
x=x,
|
||||
y=y,
|
||||
cailloux=cailloux,
|
||||
start=start,
|
||||
button=button,
|
||||
),
|
||||
)
|
38
lib/txttobinary.py
Executable file
|
@ -0,0 +1,38 @@
|
|||
def btt(dico_binaire, chaine_bin):
|
||||
"""
|
||||
Bin To Text
|
||||
In dico_binaire, chaine_bin: dict, str
|
||||
Out chaine_decomp: str
|
||||
"""
|
||||
chaine_decomp, current_code = "", ""
|
||||
dico_inv = {valeur: clef for clef, valeur in dico_binaire.items()}
|
||||
for bit in chaine_bin:
|
||||
current_code += bit
|
||||
try:
|
||||
chaine_decomp += dico_inv[current_code]
|
||||
current_code = ""
|
||||
except KeyError:
|
||||
pass
|
||||
return chaine_decomp
|
||||
|
||||
|
||||
def ttb(dico_bin, text_in):
|
||||
"""
|
||||
Text To Bin
|
||||
In dico_bin, text_in : dict, str
|
||||
out: text_bin: str
|
||||
"""
|
||||
text_bin_list = [dico_bin[elem] for elem in text_in if elem in dico_bin]
|
||||
text_bin = "".join(text_bin_list)
|
||||
return text_bin
|
||||
|
||||
|
||||
def compression(maze):
|
||||
"""
|
||||
Convertit un labyrinthe str en un array de bits.
|
||||
In maze: str
|
||||
Out: bits array
|
||||
"""
|
||||
dico_decomp = {" ": "000", ">": "100", "O": "101", ":": "011", "#": "001"}
|
||||
binmaze = ttb(dico_decomp, maze)
|
||||
return bytes(int(binmaze[i : i + 3], 2) for i in range(0, len(binmaze), 3))
|
307
main.py
Executable file
|
@ -0,0 +1,307 @@
|
|||
from lib.txttobinary import btt, compression
|
||||
from lib.maze import gen_maze
|
||||
from lib.resolv import resolve
|
||||
from tkinter import *
|
||||
import tkinter.messagebox
|
||||
from PIL import ImageTk, Image
|
||||
from copy import deepcopy
|
||||
|
||||
|
||||
def save(maze: list, bouton: Button) -> None:
|
||||
"""
|
||||
Cree un fichier binaire avec les donnees du labyrinthe.
|
||||
In tab_maze, bouton : list, Button()
|
||||
Out : None
|
||||
"""
|
||||
bouton["state"] = "disable" # evite que l'utilisateur spam le bouton ensuite
|
||||
|
||||
try: # permet de connaitre la derniere sauvegarde
|
||||
with open("save/savelist.txt", "r") as savelist:
|
||||
savefilestr = int(savelist.readline().split(";")[-2]) + 1
|
||||
except FileNotFoundError:
|
||||
savefilestr = "0"
|
||||
|
||||
str_maze = ":".join("".join(row) for row in maze) # convertit le labyrinthe en str
|
||||
bin_maze = compression(str_maze) # convert str_maze en un array de 0 et 1
|
||||
|
||||
with open(f"save/save{savefilestr}.bin", "wb") as binfile:
|
||||
binfile.write(bin_maze)
|
||||
|
||||
with open("save/savelist.txt", "a") as savelist:
|
||||
savelist.write(f"{savefilestr};") # ajoute le numero de la sauvegarde
|
||||
|
||||
tkinter.messagebox.showinfo(
|
||||
title="Amaze!",
|
||||
message=f"Labyrinthe sauvegardé!\n (~/save/save{savefilestr}.bin)",
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
def resize_image(image_path: str, width: int, height: int) -> ImageTk.PhotoImage:
|
||||
"""
|
||||
Resize and return a image with a given path to a given size.
|
||||
In image_path, width, height: str, int, int
|
||||
Out :PhotoImage()
|
||||
"""
|
||||
original_image = Image.open(image_path)
|
||||
# resampling_mode = Image.Resampling.NEAREST if width > 50 else Image.Resampling.BICUBIC # pas possible avec windows
|
||||
# resized_image = original_image.resize((width, height), resample=resampling_mode)
|
||||
resized_image = original_image.resize((width, height))
|
||||
return ImageTk.PhotoImage(resized_image)
|
||||
|
||||
|
||||
def display(tab: list, activ_save=False) -> None:
|
||||
"""
|
||||
Display the maze with sweet sweet handmade tiles.
|
||||
In tab: list
|
||||
Out : None
|
||||
"""
|
||||
root = Tk()
|
||||
root.title("Amaze!")
|
||||
root.configure(bg="white")
|
||||
root.resizable(False, False)
|
||||
root.iconphoto(False, PhotoImage(file="assets/logo.png"))
|
||||
|
||||
# definit la taille d'une cellule
|
||||
screen_height = root.winfo_screenheight() - 100
|
||||
tcellx = round(screen_height / len(tab))
|
||||
tcelly = round(screen_height / len(tab[0]))
|
||||
if tcellx > tcelly:
|
||||
tcell = tcelly
|
||||
else:
|
||||
tcell = tcellx
|
||||
del tcellx, tcelly
|
||||
|
||||
maze_canva = Canvas(
|
||||
root,
|
||||
width=(len(tab[0]) - 1) * tcell,
|
||||
height=(len(tab) - 1) * tcell,
|
||||
bg="white",
|
||||
bd=0,
|
||||
)
|
||||
|
||||
images = { # doit etre dans la loop tk pour ne pas etre garbage collected
|
||||
"a": resize_image("assets/end_up.png", tcell, tcell),
|
||||
"b": resize_image("assets/end_down.png", tcell, tcell),
|
||||
"c": resize_image("assets/end_left.png", tcell, tcell),
|
||||
"d": resize_image("assets/end_right.png", tcell, tcell),
|
||||
"ab": resize_image("assets/straight.png", tcell, tcell),
|
||||
"cd": resize_image("assets/straight_down.png", tcell, tcell),
|
||||
"da": resize_image("assets/down_right.png", tcell, tcell),
|
||||
"ca": resize_image("assets/down_left.png", tcell, tcell),
|
||||
"cb": resize_image("assets/up_left.png", tcell, tcell),
|
||||
"db": resize_image("assets/up_right.png", tcell, tcell),
|
||||
"cab": resize_image("assets/three_left.png", tcell, tcell),
|
||||
"dab": resize_image("assets/three_right.png", tcell, tcell),
|
||||
"cda": resize_image("assets/three_down.png", tcell, tcell),
|
||||
"cdb": resize_image("assets/three_up.png", tcell, tcell),
|
||||
"cdab": resize_image("assets/cross.png", tcell, tcell),
|
||||
" ": resize_image("assets/empty.png", tcell, tcell),
|
||||
"end": resize_image("assets/end.png", tcell, tcell),
|
||||
"start": resize_image("assets/start.png", tcell, tcell),
|
||||
"return": resize_image("assets/return.png", 20, 20),
|
||||
"brain": resize_image("assets/brain.png", 20, 20),
|
||||
"save": resize_image("assets/save.png", 20, 20),
|
||||
}
|
||||
|
||||
# applique les images
|
||||
for i in range(len(tab)):
|
||||
for j in range(len(tab[i])):
|
||||
name = ""
|
||||
if tab[i][j] == " ":
|
||||
for coo in [
|
||||
(j - 1, i, "c"),
|
||||
(j + 1, i, "d"),
|
||||
(j, i - 1, "a"),
|
||||
(j, i + 1, "b"),
|
||||
]:
|
||||
if 0 <= coo[0] and 0 <= coo[1]:
|
||||
if tab[coo[1]][coo[0]] in [" ", "O", ">"]:
|
||||
name += coo[2]
|
||||
maze_canva.create_image(
|
||||
j * tcell - 1, i * tcell - 1, image=images[name]
|
||||
)
|
||||
elif tab[i][j] == "O":
|
||||
maze_canva.create_image(
|
||||
j * tcell - 1, i * tcell - 1, image=images["end"]
|
||||
)
|
||||
elif tab[i][j] == ">":
|
||||
maze_canva.create_image(
|
||||
j * tcell - 1, i * tcell - 1, image=images["start"]
|
||||
)
|
||||
else:
|
||||
maze_canva.create_image(j * tcell - 1, i * tcell - 1, image=images[" "])
|
||||
maze_canva.pack(side=LEFT)
|
||||
|
||||
# cree les boutons
|
||||
buttons_canva = Canvas(root, background="white")
|
||||
save_button = Button(
|
||||
buttons_canva,
|
||||
text="Sauvegarder",
|
||||
command=lambda: save(tab, save_button),
|
||||
image=images["save"],
|
||||
compound=LEFT,
|
||||
)
|
||||
resolv_button = Button(
|
||||
buttons_canva,
|
||||
text="R\u00e9soudre",
|
||||
command=lambda: resolve(
|
||||
deepcopy(tab), maze_canva, root, tcell, button=resolv_button
|
||||
),
|
||||
image=images["brain"],
|
||||
compound=LEFT,
|
||||
)
|
||||
return_button = Button(
|
||||
buttons_canva,
|
||||
text="Retour",
|
||||
command=lambda: start(root),
|
||||
image=images["return"],
|
||||
compound=LEFT,
|
||||
)
|
||||
|
||||
# desactive le bouton "Sauvegarder"
|
||||
if not activ_save:
|
||||
save_button["state"] = "disabled"
|
||||
|
||||
resolv_button.pack(padx=20, pady=10)
|
||||
save_button.pack(padx=20, pady=10)
|
||||
return_button.pack(padx=20, pady=10)
|
||||
buttons_canva.pack(side=LEFT)
|
||||
|
||||
root.mainloop()
|
||||
|
||||
|
||||
def load_save(file_nb: int, to_close: Tk) -> None:
|
||||
"""
|
||||
Charge une sauvegarde .bin l'affiche
|
||||
In file_nb, to_close: int
|
||||
Out: None
|
||||
"""
|
||||
if to_close is not None:
|
||||
to_close.destroy()
|
||||
|
||||
with open(f"save/save{file_nb}.bin", "rb") as file:
|
||||
binary_data = file.read()
|
||||
|
||||
bin_string = "".join(
|
||||
format(byte, "03b") for byte in binary_data
|
||||
) # Les fichiers de sauvegarde sont encodes sur 3 bits
|
||||
|
||||
dico_decomp = {" ": "000", ">": "100", "O": "101", ":": "011", "#": "001"}
|
||||
deco_list = btt(dico_decomp, bin_string).split(":")
|
||||
maze = []
|
||||
for i in deco_list:
|
||||
tmp = []
|
||||
for l in i:
|
||||
tmp.append(l)
|
||||
maze.append(tmp)
|
||||
|
||||
display(maze)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def valid_values(varx: StringVar, vary: StringVar, to_close: Tk, info: Label) -> None:
|
||||
"""
|
||||
verifie des les valeurs x et y de creation du labyrinthe sont correctes
|
||||
In varx, vary, to_close, info = StringVar(), StringVar(), Tk(), Label()
|
||||
Out : None
|
||||
"""
|
||||
try:
|
||||
x, y = int(varx.get()), int(vary.get())
|
||||
if x < 5 or x > 500 or y < 5 or y > 500:
|
||||
info.config(
|
||||
text="La taille du labyrinthe doit \u00eatre\n entre 5x5 et 500x500 (\u25d4\u005f\u25d4)",
|
||||
foreground="red",
|
||||
)
|
||||
else:
|
||||
to_close.destroy()
|
||||
maze = gen_maze(x, y)
|
||||
display(maze, True)
|
||||
except:
|
||||
info.config(
|
||||
text="Vous devriez essayer avec\n des chiffres (\uffe2\u005f\uffe2)",
|
||||
foreground="red",
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def start(to_close=None) -> None:
|
||||
"""
|
||||
Affiche la fenetre de selection du labyrinthe
|
||||
In to_close: Tk()
|
||||
Out: None
|
||||
"""
|
||||
if to_close is not None:
|
||||
to_close.destroy()
|
||||
|
||||
root = Tk()
|
||||
root.title("Amaze!")
|
||||
root.resizable(False, False)
|
||||
root.configure()
|
||||
root.iconphoto(False, PhotoImage(file="assets/logo.png"))
|
||||
|
||||
top_frame = Frame(root)
|
||||
entry_frame = Frame(top_frame)
|
||||
bottom_frame = Frame(root)
|
||||
|
||||
info_label = Label(
|
||||
top_frame,
|
||||
text="Super Labyrinthe Mega Ultra HD\n 4K Premium ChatPGT IA 14.5",
|
||||
font=("Times New Roman", 15, "bold"),
|
||||
justify=CENTER,
|
||||
foreground="blue",
|
||||
)
|
||||
info_label.pack_propagate(0)
|
||||
info_label.pack(side=TOP)
|
||||
txtx = Label(entry_frame, text="x", font=("Times New Roman", 11, "bold"))
|
||||
|
||||
sizex_var = StringVar(root)
|
||||
sizex_var.set("10")
|
||||
sizey_var = StringVar(root)
|
||||
sizey_var.set("10")
|
||||
|
||||
sizex_entry = Entry(entry_frame, textvariable=sizex_var)
|
||||
sizex_entry.pack(padx=5, pady=10, side="left")
|
||||
|
||||
txtx.pack(side=LEFT)
|
||||
|
||||
sizey_entry = Entry(entry_frame, textvariable=sizey_var)
|
||||
sizey_entry.pack(padx=5, pady=10, side="left")
|
||||
|
||||
create_button = Button(
|
||||
top_frame,
|
||||
text="G\u00e9n\u00e9rer un labyrinthe",
|
||||
command=lambda: valid_values(sizex_var, sizey_var, root, info_label),
|
||||
)
|
||||
create_button.pack(pady=10, side="bottom")
|
||||
|
||||
try:
|
||||
with open("save/savelist.txt", "r") as savelist:
|
||||
option_save = savelist.readline().split(";")[:-1]
|
||||
|
||||
save_var = StringVar(root)
|
||||
save_var.set(option_save[0])
|
||||
|
||||
option_menu_save = OptionMenu(bottom_frame, save_var, *option_save)
|
||||
save_button = Button(
|
||||
bottom_frame,
|
||||
text="Charger un labyrinthe",
|
||||
command=lambda: load_save(save_var.get(), root),
|
||||
)
|
||||
save_button.pack(pady=10, side="bottom")
|
||||
option_menu_save.pack(pady=10, side="bottom")
|
||||
|
||||
entry_frame.pack()
|
||||
top_frame.pack(padx=20, pady=20, side="top")
|
||||
bottom_frame.pack(padx=20, pady=20)
|
||||
except FileNotFoundError:
|
||||
top_frame.pack(padx=20, pady=20, side="top")
|
||||
entry_frame.pack()
|
||||
create_button.pack(pady=10)
|
||||
|
||||
root.mainloop()
|
||||
|
||||
|
||||
start()
|