diff --git a/data/fond.png b/data/fond.png new file mode 100755 index 0000000..a9faec8 Binary files /dev/null and b/data/fond.png differ diff --git a/data/logo.png b/data/logo.png new file mode 100755 index 0000000..ae1f7fb Binary files /dev/null and b/data/logo.png differ diff --git a/main.py b/main.py new file mode 100755 index 0000000..40c0503 --- /dev/null +++ b/main.py @@ -0,0 +1,452 @@ +import tkinter as tk +from tkinter import ttk +import tkinter.messagebox +from random import randint + + +class Snake: + """ + cree un serpent + Entree : int + Sortie : None + """ + + def __init__(self, v, s, cs): + """ + Parametre le serpent + Entree : self, int + Sortie : None + """ + self.__cells_to_wait = 0 + self.__velocity = v + self.__cells_size = cs + self.__direction = "Down" + self.__snake = [ + canvas.create_rectangle( + 245 + i, + 150, + 245 + i + cs, + 150 + cs, + width=2, + outline="#081820", + fill="#E0F8D0", + ) + for i in range(0, s * v, v) + ] + canvas.itemconfigure( + self.__snake[0], fill="#081820" + ) # change la couleur de la tete + + def __getitem__(self, item): + """ + renvoit certaines informations sur la liste __snake + Entree : self, int + Sortie : list, int, class, None + """ + if item == 0: + return canvas.coords(self.__snake[0]) + if item == 1: + return len(self.__snake) + if item == 3: + return self.__snake[0] + if item == 4: + return self.__snake + if item == 5: + return self.__snake[-1] + return None + + def diy(self, x, color): + """ + change la couleur du serpent + Entree : self, int, str + Sortie : None + """ + if x >= 1: + canvas.itemconfig(self.__snake[x], fill=color) + canvas.after(50, lambda: self.diy(x - 1, color)) # prochaine cellule + return None + + def move(self, color): + """ + fait avancer le serpent et informe si le serpent sort du cadre + Entree : self + Sortie : bool + """ + # for i in range(len(self.__snake) - 1, 0, -1): # bouge le corp du serpent + # canvas.move(self.__snake[i], canvas.coords(self.__snake[i - 1])[0] - canvas.coords(self.__snake[i])[0], + # canvas.coords(self.__snake[i - 1])[1] - canvas.coords(self.__snake[i])[1]) + if self.__cells_to_wait <= 0: + canvas.delete(self.__snake.pop(-1)) + else: + self.__cells_to_wait -= 1 + + # bouge la tête du serpent + head_coo = canvas.coords(self.__snake[0]) + canvas.itemconfig(self.__snake[0], fill="#E0F8D0") + if self.__direction == "Up": + # canvas.move(self.__snake[0], 0, -self.__velocity) + self.__snake = [ + canvas.create_rectangle( + head_coo[0], + head_coo[1] - self.__velocity, + head_coo[2], + head_coo[3] - self.__velocity, + width=2, + outline=color, + fill="#081820", + ) + ] + self.__snake + + elif self.__direction == "Down": + # canvas.move(self.__snake[0], 0, self.__velocity) + self.__snake = [ + canvas.create_rectangle( + head_coo[0], + head_coo[1] + self.__velocity, + head_coo[2], + head_coo[3] + self.__velocity, + width=2, + outline=color, + fill="#081820", + ) + ] + self.__snake + + elif self.__direction == "Left": + # canvas.move(self.__snake[0], -self.__velocity, 0) + self.__snake = [ + canvas.create_rectangle( + head_coo[0] - self.__velocity, + head_coo[1], + head_coo[2] - self.__velocity, + head_coo[3], + width=2, + outline=color, + fill="#081820", + ) + ] + self.__snake + + elif self.__direction == "Right": + # canvas.move(self.__snake[0], self.__velocity, 0) + self.__snake = [ + canvas.create_rectangle( + head_coo[0] + self.__velocity, + head_coo[1], + head_coo[2] + self.__velocity, + head_coo[3], + width=2, + outline=color, + fill="#081820", + ) + ] + self.__snake + + return None + + def change_dir(self, event): + """ + change la direction de la tête et empeche le retour arriere + Entree : self, event + Sortie : None + """ + head = canvas.coords(self[3]) + cells = self.__snake + if event.keysym == "Up" and cells[1] in canvas.find_overlapping( + head[0], head[1] - self.__velocity, head[2], head[3] - self.__velocity + ): + return None + if event.keysym == "Down" and cells[1] in canvas.find_overlapping( + head[0], head[1] + self.__velocity, head[2], head[3] + self.__velocity + ): + return None + if event.keysym == "Left" and cells[1] in canvas.find_overlapping( + head[0] - self.__velocity, head[1], head[2] - self.__velocity, head[3] + ): + return None + if event.keysym == "Right" and cells[1] in canvas.find_overlapping( + head[0] + self.__velocity, head[1], head[2] + self.__velocity, head[3] + ): + return None + self.__direction = event.keysym # sinon, on applique le changement de direction + return None + + def add_cells(self, x): + """ + ajoute x cellules au serpent + Entree : self, int + Sortie : None + """ + # for i in range(x): + # self.__snake.append(canvas.create_rectangle(canvas.coords(self.__snake[-1])[0], + # canvas.coords(self.__snake[-1])[1], + # canvas.coords(self.__snake[-1])[2], + # canvas.coords(self.__snake[-1])[3], + # width=2, outline='#081820', fill="#E0F8D0")) + self.__cells_to_wait = x + return None + + def self_eater(self, pomme): + """ + verifie que le serpent ne rentre pas en contact avec lui même + Entree : self, instance de apple + Sortie : bool + """ + c_s = canvas.coords(self[3]) + tup = canvas.find_overlapping(c_s[0], c_s[1], c_s[2], c_s[3]) + if len(tup) > 2: + if pomme[3] in tup: + return False + return True + return False + + +class Apple: + """ + cree une pomme aux coordonnée x, y et lui donne un type + """ + + def __init__(self, s): + """ + parametre la class + Entree : self, int + Sortie : None + """ + if randint(1, 10) == 10: + self.__color = "yellow" + else: + self.__color = "red" + y = randint(20, 450) + x = randint(20, 450) + while len(canvas.find_overlapping(x, y, x + 10, y + 10)) > 1: + y = randint(20, 450) + x = randint(20, 450) + self.__apple = canvas.create_oval( + x, y, x + s, y + s, fill=self.__color, width=2, outline="#081820" + ) + + def __getitem__(self, item): + """ + revoit des informations sur l'instance + Entree : self, int + Sortie : list, instance, str + """ + if item == 0: + return canvas.coords(self.__apple) + if item == 1: + return self.__color + if item == 3: + return self.__apple + return None + + def delete_a(self): + """ + suprime la pomme + Entree : self + Sortie : None + """ + canvas.delete(self.__apple) + return None + + +def info(): + """ + affiche une boite d'information + Entree : None + Sortie : None + """ + tkinter.messagebox.showinfo( + title=None, + message="Blockade, créé par Gremlin en 1976, est le premier jeu de type snake connu. " + "Rapidement aprés sa création, il est devenu un succés sur les bornes " + "d'arcade. Les premières" + "apparitions du terme 'snake' remonte plutôt à 1982 avec des clones tels que " + "'Snake Byte'.\n\nLe clone ci-présent a été fait par Joachim Rey.", + ) + return None + + +def main(): + """ + gere le jeu + Entree : None + Sortie : None + """ + + def start(diff): + """ + commence le jeu + Entree : int + Sortie : None + """ + # reset le canva + canvas.delete("all") + canvas.create_image(0, 0, image=fond, anchor="nw") + canvas.create_window(260, 565, window=label) + canvas.create_rectangle(20, 20, 520, 520, outline="red") + + # cree les parametre du jeu + if diff == 1 or diff == 0: + serpent = Snake(6, 6, 5) + diff = "facile" + elif diff == 2: + serpent = Snake(11, 6, 10) + diff = "normal" + else: + serpent = Snake(21, 6, 20) + diff = "HARDCORE" + pomme = Apple(10) + score = 0 + + # attache les touches aux actions + root.bind("", serpent.change_dir) + root.bind("", serpent.change_dir) + root.bind("", serpent.change_dir) + root.bind("", serpent.change_dir) + label.config(text=f"score: {score} Taille: {serpent[1]}") + + # lance le jeu + game(serpent, pomme, score, diff) + + return None + + def game(serpent, pomme, score, diff): + """ + gere les deplacement du serpent, l'apparition de la pomme et la fin du jeu + Entree : instance de serpent, de pomme, int + Sortie : None + """ + c_p = canvas.coords(pomme[3]) + h_color = "#081820" + if serpent[3] in canvas.find_overlapping(c_p[0], c_p[1], c_p[2], c_p[3]): + if pomme[1] == "red": + score += 1 + serpent.add_cells(serpent[1] * 20 // 100) + h_color = "red" + else: + score += 5 + serpent.add_cells(serpent[1] * 50 // 100) + h_color = "yellow" + pomme.delete_a() + pomme = Apple(10) + label.config(text=f"score: {score} Taille: {serpent[1]}") + + if serpent.self_eater(pomme): + serpent.diy(serpent[1] - 1, "red") + rep = tkinter.messagebox.askretrycancel( + title=None, message="Oups, vous êtes devenu de la purée de serpent." + ) + with open("data/save.txt", "r") as file: + save = file.read() + if save.split(";")[0] == "" or int(save.split(";")[0]) < score: + with open("data/save.txt", "w") as file: + file.write(f"{str(score)};{diff}") + if rep: + main() + return None + else: + root.destroy() + return None + + else: + serpent.move(h_color) + canvas.after(60, lambda: game(serpent, pomme, score, diff)) + return None + + def diff_change(*args): # scale met par defaut un parametre + """ + change le texte de diff_affi + Entree : event + Sortie : None + """ + if round(diff.get()) == 1 or round(diff.get()) == 0: + diff_affi.configure(text="Difficulté: Facile", foreground="green") + elif round(diff.get()) == 2: + diff_affi.configure(text="Difficulté: Normal", foreground="black") + else: + diff_affi.configure(text="Difficulté: HARDCORE", foreground="red") + return None + + # reset la canva + canvas.delete("test") + + # tente de recuperer l'ancien meilleur score + try: + with open("data/save.txt", "r") as file: + save_s = file.read() + text_score = ( + "Meilleur score:\n" + + f"{save_s.split(';')[0]} en difficulté {save_s.split(';')[1]}" + ) + except FileNotFoundError: + with open("data/save.txt", "w") as file: + file.write("0;None") + text_score = "Meilleur score:\nVous n'avez pas de scores pour le moment\n lancez une partie :) !" + + # configure les boutons + best_score = ttk.Label( + canvas, + text=text_score, + font=("Helvetica", 14), + background="#E0F8D0", + justify="center", + ) + label = ttk.Label( + root, + text="Bienvenu sur Blockade Py !", + font=("Helvetica", 14), + background="#E0F8D0", + ) + diff = tk.DoubleVar() + diff_selec = ttk.Scale( + canvas, from_=1, to=3, orient="horizontal", command=diff_change, variable=diff + ) + start_button = ttk.Button( + canvas, + text="Commencer", + command=lambda: start(round(diff.get())), + style="my.TButton", + ) + info_button = ttk.Button( + canvas, text="?", command=info, style="info.TButton", width=3 + ) + diff_affi = ttk.Label( + root, + text="Difficulté: Facile", + font=("Helvetica", 14), + background="#E0F8D0", + foreground="green", + ) + + # affiche les widgets + canvas.create_window(270, 70, window=best_score) + canvas.create_window(270, 565, window=label) + canvas.create_window(499, 563, window=info_button) + canvas.create_window(270, 220, window=diff_affi) + canvas.create_window(270, 250, window=diff_selec) + canvas.create_window(270, 300, window=start_button) + canvas.create_image(0, 0, image=fond, anchor="nw") + + return None + + +if __name__ == "__main__": + # création de la fenetre + root = tk.Tk() + root.title("Snack") + root.iconphoto(False, tk.PhotoImage(file="data/logo.png")) + root.resizable(False, False) + + # definition du canva + fond = tk.PhotoImage(file="data/fond.png") + canvas = tk.Canvas(root, width=540, height=600, bg="black") + canvas.pack(fill="both", expand=True) + + # style des boutons (ttk) + style = ttk.Style(root) + style.theme_use("clam") + style.configure("my.TButton", bordercolor="#081820", bg="#e0f8d0") + style.configure("info.Tbutton", borderwidth=0, bordercolor="#081820", bg="#e0f8d0") + + # demarre le jeu + main() + + # boucle de la fenetre + root.mainloop()