Ejemplo n.º 1
0
class Fenetre(Tk):
    def __init__(self):
        super().__init__()

        # Nom de la fenêtre.
        self.title("Échiquier")

        self.partie = Partie()

        #Bouton X (pour quitter)
        self.protocol('WM_DELETE_WINDOW', self.message_quitter)

        # Truc pour le redimensionnement automatique des éléments de la fenêtre.
        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(0, weight=1)

        # Création du canvas échiquier.
        self.canvas_echiquier = CanvasEchiquier(self, 60, self.partie)
        self.canvas_echiquier.grid(sticky=NSEW)

        ##########################################################
        #                                                        #
        #                    VISUEL                              #
        #                                                        #
        ##########################################################
        # Étiquette d'information et de sélection des pièces
        self.messages = Label(self)
        self.messages['foreground'] = 'black'
        self.messages['text'] = "Bienvenue au super jeux d'échec!"
        self.messages.grid(row=1, sticky='w')

        # # Étiquette d'information sur le joueur courant
        self.messages1 = Label(self)
        self.messages1[
            'text'] = "Au tour du joueur: " + self.partie.joueur_actif.upper()
        self.messages1.grid(row=2, sticky='w')
        self.messages1['foreground'] = 'blue'

        # Création du frame a droite du canevas
        self.monFramePrincipal = Frame(self)
        self.monFramePrincipal.grid(row=0, column=1, sticky='n')

        # FRAME a DROITE: Fenetre pour afficher la liste des déplacements effectués
        self.mon_frame1 = LabelFrame(self.monFramePrincipal,
                                     text="Les déplacements ",
                                     borderwidth=2,
                                     relief=RIDGE,
                                     padx=5,
                                     pady=5)
        self.mon_frame1.grid(row=0, column=0, sticky='n')
        self.yScroll = Scrollbar(self.mon_frame1, orient=VERTICAL)
        self.yScroll.grid(row=0, column=1, sticky=N + S)
        #small_font = font(size=5)
        self.liste1 = Listbox(self.mon_frame1, yscrollcommand=self.yScroll.set)
        self.liste1 = Listbox(self.mon_frame1)
        self.liste1.grid(row=0, column=0)
        self.yScroll['command'] = self.liste1.yview

        # Creation d'un espace pour mettre les 2 fenetres de pièces mangées (un sous-Frame)
        self.monSousFrame = Frame(self.monFramePrincipal)
        self.monSousFrame.grid(row=1, column=0, sticky='n')

        # FRAME a DROITE: Fenetre pour afficher les pieces blanches mangées
        self.mon_frame2 = LabelFrame(self.monSousFrame,
                                     text="Les blancs\nmangés ",
                                     borderwidth=2,
                                     relief=RIDGE,
                                     padx=5,
                                     pady=5,
                                     width=7)
        self.mon_frame2.grid(row=0, column=0, sticky='n')
        self.yScroll = Scrollbar(self.mon_frame2, orient=VERTICAL)
        self.yScroll.grid(row=0, column=1, sticky=N + S)
        self.liste2 = Listbox(self.mon_frame2, yscrollcommand=self.yScroll.set)
        self.liste2 = Listbox(self.mon_frame2, width=7)
        self.liste2.grid(row=0, column=0)
        self.yScroll['command'] = self.liste2.yview

        # FRAME a DROITE: Fenetre pour afficher les pieces noires mangées
        self.mon_frame2 = LabelFrame(self.monSousFrame,
                                     text="Les noirs\nmangés ",
                                     borderwidth=2,
                                     relief=RIDGE,
                                     padx=5,
                                     pady=5,
                                     width=7)
        self.mon_frame2.grid(row=0, column=1, sticky='n')
        self.yScroll = Scrollbar(self.mon_frame2, orient=VERTICAL)
        self.yScroll.grid(row=0, column=1, sticky=N + S)
        self.liste3 = Listbox(self.mon_frame2, yscrollcommand=self.yScroll.set)
        self.liste3 = Listbox(self.mon_frame2, width=7)
        self.liste3.grid(row=0, column=0)
        self.yScroll['command'] = self.liste3.yview

        # FRAME a DROITE: Bouton pour se connecter au site web des intrusctions d'echec
        self.mon_frame3 = Frame(self.monFramePrincipal,
                                borderwidth=2,
                                relief=RIDGE,
                                padx=5,
                                pady=5)
        self.mon_frame3.grid(row=2, column=0, sticky='n')
        but1 = Button(self.mon_frame3,
                      text="Lien web pour accéder\naux règles du jeux!",
                      command=self.ouvrirURL).grid(row=0, column=0)

        # Frame pour les options de jeux en bas de l'échiquier
        self.mon_frame = LabelFrame(self,
                                    text="Options de partie",
                                    borderwidth=2,
                                    relief=RIDGE,
                                    padx=5,
                                    pady=5)
        self.mon_frame.grid(row=4, column=0, sticky='w')
        bouton_sauver = Button(self.mon_frame,
                               text="Sauvegarder",
                               command=self.sauvergarder).grid(row=0, column=0)
        bouton_charge = Button(self.mon_frame,
                               text="Charger",
                               command=self.message_charger).grid(row=0,
                                                                  column=1)
        bouton_demarrer = Button(self.mon_frame,
                                 text="Redémarrage",
                                 command=self.message_reinitialiser).grid(
                                     row=0, column=2)
        bouton_annuler = Button(self.mon_frame,
                                text="Annuler dernier mouvement",
                                command=self.annulerDernierMouvement).grid(
                                    row=0, column=3)

        # On lie un clic sur le CanvasEchiquier à une méthode.
        self.canvas_echiquier.bind('<Button-1>', self.selectionner)

        self.piece_a_deplacer = None
        self.position_piece_a_deplacer = None

        #Pour que x et y soient accessibles dans selectionner ET dans creer_carre_selection
        self.x = 1
        self.y = 1

    def message_charger(self):
        """"
            Ouvre une fenêtre s'assurant que l'utilisateur veut bien charger.
            Lui propose de sauvegarder la partie.
        """
        message = messagebox.askyesno(
            'Avertissement',
            'Voulez-vous vraiment charger une autre partie? \nCette partie sera perdue.',
            icon='warning')
        if message is True:
            self.charger()

    def message_reinitialiser(self):
        """"
            Ouvre une fenêtre s'assurant que l'utilisateur veut bien réinitialiser.
            Lui propose de sauvegarder la partie.
        """
        message = messagebox.askyesnocancel(
            'Avertissement',
            'Voulez-vous sauvgarder avant de redémarrer la partie? \nTout changement non sauvegardé sera perdu.',
            icon='warning')
        if message is True:
            self.sauvergarder()
            self.reinitialiser()
        elif message is False:
            self.reinitialiser()

    def message_quitter(self):
        """"
            Ouvre une fenêtre s'assurant que l'utilisateur veut bien quitter.
            Lui propose de sauvegarder la partie.
        """
        message = messagebox.askyesnocancel(
            'Avertissement',
            'Voulez-vous sauvgarder avant de quitter? \nTout changement non sauvegardé sera perdu.',
            icon='warning')
        if message is True:
            self.sauvergarder()
            self.destroy()
        elif message is False:
            self.destroy()

    def ouvrirURL(self):
        '''
        Permet d'ouvrir un ULR qui donne sur les règlements du jeux d'échec
        '''
        url = 'https://fr.wikipedia.org/wiki/Règles_du_jeu_d%27échecs'
        webbrowser.open_new(url)

    def reinitialiser(self):
        '''
        Permet de raffraichir les cases, les pieces, les pieces mangées et les informations dans les Listbox
        pour les déplacements et les pièces blanches et noires.
        '''
        self.partie.echiquier.initialiser_echiquier_depart()
        self.partie.joueur_actif = 'blanc'
        self.messages['text'] = ''
        self.canvas_echiquier.raffraichir_cases()
        self.canvas_echiquier.raffraichir_pieces()
        self.rafraichirPiecesMangees()
        self.liste1.delete(0, END)
        self.liste2.delete(0, END)
        self.liste3.delete(0, END)

    def entrer_nom_sauvegarde(self):
        """"
            On affiche une fenêtre demandant à l'utlisateur d'entrer un nom pour la partie à sauvegarder.
            Pour charger une partie sauvegardée, il faut entrer le nom de la sauvegarde choisi ici.
            Par défaut, le nom de la sauvegarde est 'sauvegarde'.
        """
        popup = Tk()
        popup.withdraw()
        nom_sauvegarde = simpledialog.askstring(
            title="Sauvegarder",
            prompt="Entrez le nom de la partie à sauvegarder:",
            initialvalue="sauvegarde")

        self.partie.nom_fichier_sauvegarde = nom_sauvegarde

    def recuperer_nom_sauvegarde(self):
        """"
            On affiche une fenêtre demandant à l'utlisateur d'entrer le nom d'une sauvegarde existante.
            Ce nom sera stocké dans self.partie.nom_fichier_sauvegarde.
        """
        popup = Tk()
        popup.withdraw()
        nom_sauvegarde = simpledialog.askstring(
            title="Charger",
            prompt="Entrez le nom d'une partie sauvegardée existante:")

        self.partie.nom_fichier_sauvegarde = nom_sauvegarde

    def sauvergarder(self):
        """"
            Sauvegarde la position des pièces dans l'échiquier au moment de la sauvegarde.
            La sauvegarde est faite au nom entré par l'utilisateur dans self.partie.nom_fichier_sauvegarde.
        """
        self.entrer_nom_sauvegarde()
        if self.partie.nom_fichier_sauvegarde != '' and self.partie.nom_fichier_sauvegarde is not None:
            self.partie.sauvegarder_partie()

        self.canvas_echiquier.raffraichir_cases()
        self.canvas_echiquier.raffraichir_pieces()

    def charger(self):
        """"
        Permet de charger une partie existante.
        Si le nom entré n'existe pas, retourne une erreur.
        Si le fichier existe, il charge l'échiqier.
        """
        self.recuperer_nom_sauvegarde()
        try:
            self.partie.charger_partie()
        except:
            popup = Tk()
            popup.title('Erreur')

            label = Label(
                popup,
                text=
                "Le nom de sauvegarde entré n'existe pas. Impossible de charger la partie."
            )
            label.grid()
            popup.mainloop()

        self.canvas_echiquier.raffraichir_cases()
        self.canvas_echiquier.raffraichir_pieces()

    def annulerDernierMouvement(self):
        '''
        Permet d'annuler le dernier mouvement et de mettre à jour l'affichage
        '''
        try:
            self.partie.annulerDernierMouvement()
            self.canvas_echiquier.raffraichir_cases()
            self.canvas_echiquier.raffraichir_pieces()

            self.liste1.delete(END)
            self.messages1[
                'text'] = "Au tour du joueur: " + self.partie.joueur_actif.upper(
                )
            self.rafraichirPiecesMangees()
        except:
            self.messages[
                'text'] = "Vous ne pouvez pas retourner davantage en arrière."
            self.messages['foreground'] = 'red'

    def rafraichirPiecesMangees(self):
        '''
        Permet de rafraichir l'affichage des pièces blanches et noires mangées
        '''
        self.liste2.delete(0, END)
        for i in self.partie.gapBlanc:
            self.liste2.insert(END, i)
        self.liste3.delete(0, END)
        for i in self.partie.gapNoir:
            self.liste3.insert(END, i)

    def roi_en_rouge(self):
        """"
            Si le Roi du joueur actif est en échec, un carré rouge est créé sous le Roi menacé.
        """
        if self.partie.mon_roi_en_echec():
            #On supprime les pieces et les cases
            # self.canvas_echiquier.delete('case')
            # self.canvas_echiquier.delete('piece')

            #On determine la position du Roi en échec:
            position_roi = self.partie.position_mon_roi(
                self.partie.joueur_actif)

            #Écriture de la case du roi en pixels
            index_colonne = self.partie.echiquier.lettres_colonnes.index(
                position_roi[0])
            coordonnees_x1 = index_colonne * self.canvas_echiquier.n_pixels_par_case
            coordonnees_x2 = coordonnees_x1 + self.canvas_echiquier.n_pixels_par_case

            coordonnees_y1 = (7 - self.partie.echiquier.chiffres_rangees.index(
                position_roi[1])) * self.canvas_echiquier.n_pixels_par_case
            coordonnees_y2 = coordonnees_y1 + self.canvas_echiquier.n_pixels_par_case

            #On redessine les cases
            # self.canvas_echiquier.dessiner_cases()

            #Dessin du carré rouge
            self.canvas_echiquier.create_rectangle(coordonnees_x1,
                                                   coordonnees_y1,
                                                   coordonnees_x2,
                                                   coordonnees_y2,
                                                   fill='red')
            #On redessine les pieces
            # self.canvas_echiquier.dessiner_pieces()

    def creer_carre_selection(self):
        """"
            Dessine un carré rose à la position (x,y).
            Méthode appelée pour identifier la case sélectionnée par le joueur.
        """

        #Dessiner le carre
        self.canvas_echiquier.create_rectangle(
            (self.x // self.canvas_echiquier.n_pixels_par_case) *
            self.canvas_echiquier.n_pixels_par_case,
            (self.y // self.canvas_echiquier.n_pixels_par_case) *
            self.canvas_echiquier.n_pixels_par_case,
            ((self.x // self.canvas_echiquier.n_pixels_par_case) + 1) *
            self.canvas_echiquier.n_pixels_par_case,
            ((self.y // self.canvas_echiquier.n_pixels_par_case) + 1) *
            self.canvas_echiquier.n_pixels_par_case,
            fill='pink',
            tags='select')

    def selectionner(self, event):
        """"
            Identifie ou le joueur a cliqué sur le canvas.
            Permet de sélectionner les pièces et de les déplacer.
            S'assure que les sélections et les déplacements sont valides selon les règles du jeu d'échec.
        """
        self.x = event.x
        self.y = event.y

        # On trouve le numéro de ligne/colonne en divisant les positions en y/x par le nombre de pixels par case.
        ligne = event.y // self.canvas_echiquier.n_pixels_par_case
        colonne = event.x // self.canvas_echiquier.n_pixels_par_case
        position = "{}{}".format(
            self.canvas_echiquier.lettres_colonnes[colonne],
            self.canvas_echiquier.chiffres_rangees[
                self.canvas_echiquier.n_lignes - ligne - 1])
        self.position = position

        piece_selectionnee = self.partie.echiquier.recuperer_piece_a_position(
            position)

        # Si la case sélectionnée est vide
        if piece_selectionnee is None:
            if self.piece_a_deplacer is None:  #Si aucune pièce n'est stockée dans self.piece_a_deplacer
                # Dessin de l'echiquier
                self.canvas_echiquier.delete('case')
                self.canvas_echiquier.delete('piece')
                self.canvas_echiquier.dessiner_cases()
                self.roi_en_rouge()
                self.canvas_echiquier.dessiner_pieces()

                self.messages[
                    'text'] = f"Il n'y a aucune pièce à la position {position}."
                self.messages['foreground'] = 'red'

            else:  #Si un pièce est stockée dans self.piece_a_deplacer
                try:  #On essaye d'effectuer le déplacement
                    self.partie.deplacer(self.position_piece_a_deplacer,
                                         position)

                    #Derniers déplacements et pièces mangées
                    self.liste1.insert(END, self.partie.dernierDeplacement)
                    self.liste2.delete(0, END)
                    for i in self.partie.gapBlanc:
                        self.liste2.insert(END, i)
                    self.liste3.delete(0, END)
                    for i in self.partie.gapNoir:
                        self.liste3.insert(END, i)

                    self.piece_a_deplacer = None
                    self.position_piece_a_deplacer = None

                    # Dessin de l'echiquier
                    self.canvas_echiquier.delete('case')
                    self.canvas_echiquier.delete('piece')
                    self.canvas_echiquier.delete('select')
                    self.canvas_echiquier.dessiner_cases()
                    self.roi_en_rouge()
                    self.canvas_echiquier.dessiner_pieces()

                    self.messages['text'] = ''
                except:  #Si le déplacement est non valide
                    self.piece_a_deplacer = None
                    self.position_piece_a_deplacer = None

                    # Dessin de l'echiquier
                    self.canvas_echiquier.delete('case')
                    self.canvas_echiquier.delete('piece')
                    self.canvas_echiquier.delete('select')
                    self.canvas_echiquier.dessiner_cases()
                    self.roi_en_rouge()
                    self.canvas_echiquier.dessiner_pieces()

                    self.messages['text'] = f"Le déplacement est invalide."
                    self.messages['foreground'] = 'red'
        #Si la case sélectionnée contient une pièce appartenant au joueur actif
        elif piece_selectionnee.couleur == self.partie.joueur_actif:
            if self.piece_a_deplacer is None:  #Si aucune pièce n'est stockée dans self.piece_a_deplacer, on emagasine celle slectionnée
                self.piece_a_deplacer = piece_selectionnee
                self.position_piece_a_deplacer = position

                #Dessin de l'echiquier
                self.canvas_echiquier.delete('case')
                self.canvas_echiquier.delete('piece')
                self.canvas_echiquier.dessiner_cases()
                self.creer_carre_selection()
                self.roi_en_rouge()
                self.canvas_echiquier.dessiner_pieces()

                self.messages[
                    'text'] = f'Pièce sélectionnée : {self.piece_a_deplacer} à la position {position}.'
                self.messages['foreground'] = 'black'
            elif self.piece_a_deplacer == piece_selectionnee:  #1c

                self.piece_a_deplacer = None
                self.position_piece_a_deplacer = None

                # Dessin de l'echiquier
                self.canvas_echiquier.delete('case')
                self.canvas_echiquier.delete('piece')
                self.canvas_echiquier.delete('select')
                self.canvas_echiquier.dessiner_cases()
                self.roi_en_rouge()
                self.canvas_echiquier.dessiner_pieces()

                self.messages['text'] = f'Aucune pièce sélectionnée.'
                self.messages['foreground'] = 'black'
            else:  # 1b
                #Roque
                if isinstance(piece_selectionnee, Tour) and isinstance(
                        self.piece_a_deplacer, Roi):
                    if self.partie.roque_est_valide(
                            self.position_piece_a_deplacer, position):
                        self.partie.roquer(self.position_piece_a_deplacer,
                                           position)

                        #Derniers déplacements et pièces mangées
                        self.liste1.insert(END, self.partie.dernierDeplacement)
                        self.liste2.delete(0, END)
                        for i in self.partie.gapBlanc:
                            self.liste2.insert(END, i)
                        self.liste3.delete(0, END)
                        for i in self.partie.gapNoir:
                            self.liste3.insert(END, i)
                        self.piece_a_deplacer = None
                        self.position_piece_a_deplacer = None

                        # Dessin de l'echiquier
                        self.canvas_echiquier.delete('case')
                        self.canvas_echiquier.delete('piece')
                        self.canvas_echiquier.delete('select')
                        self.canvas_echiquier.dessiner_cases()
                        self.roi_en_rouge()
                        self.canvas_echiquier.dessiner_pieces()
                        self.messages['text'] = ''
                    else:
                        self.piece_a_deplacer = None
                        self.position_piece_a_deplacer = None

                        # Dessin de l'echiquier
                        self.canvas_echiquier.delete('case')
                        self.canvas_echiquier.delete('piece')
                        self.canvas_echiquier.delete('select')
                        self.canvas_echiquier.dessiner_cases()
                        self.roi_en_rouge()
                        self.canvas_echiquier.dessiner_pieces()

                        self.messages['text'] = f"Le déplacement est invalide."
                        self.messages['foreground'] = 'red'

                #Si on tente de sélectionner une 2e fois la même case, on la désélectionne
                else:
                    self.piece_a_deplacer = piece_selectionnee
                    self.position_piece_a_deplacer = position

                    # Dessin de l'echiquier
                    self.canvas_echiquier.delete('case')
                    self.canvas_echiquier.delete('piece')
                    self.canvas_echiquier.delete('select')
                    self.canvas_echiquier.dessiner_cases()
                    self.creer_carre_selection()
                    self.roi_en_rouge()
                    self.canvas_echiquier.dessiner_pieces()

                    self.messages[
                        'text'] = f'Pièce sélectionnée : {self.piece_a_deplacer} à la position {position}.'
                    self.messages['foreground'] = 'black'
        #Si la case sélectionnée contient une pièce appartenant à l'adversaire
        elif piece_selectionnee.couleur != self.partie.joueur_actif:
            #Si aucune pièce n'est stockée dans self.piece_a_deplacer
            if self.piece_a_deplacer is None:
                # Dessin de l'echiquier
                self.canvas_echiquier.delete('case')
                self.canvas_echiquier.delete('piece')
                self.canvas_echiquier.dessiner_cases()
                self.roi_en_rouge()
                self.canvas_echiquier.dessiner_pieces()

                self.messages[
                    'text'] = f"La pièce à la position {position} n'est pas à vous!"
                self.messages['foreground'] = 'red'
            #Si une pièce est stockée dans self.piece_a_deplacer
            else:
                try:  #On tente de la déplacer jusqu'à la case sélectionnée
                    self.partie.deplacer(self.position_piece_a_deplacer,
                                         position)

                    # Derniers déplacements et pièces mangées
                    self.liste1.insert(END, self.partie.dernierDeplacement)
                    self.liste2.delete(0, END)
                    for i in self.partie.gapBlanc:
                        self.liste2.insert(END, i)
                    self.liste3.delete(0, END)
                    for i in self.partie.gapNoir:
                        self.liste3.insert(END, i)

                    self.piece_a_deplacer = None
                    self.position_piece_a_deplacer = None

                    # Dessin de l'echiquier
                    self.canvas_echiquier.delete('case')
                    self.canvas_echiquier.delete('piece')
                    self.canvas_echiquier.delete('select')
                    self.canvas_echiquier.dessiner_cases()
                    self.roi_en_rouge()
                    self.canvas_echiquier.dessiner_pieces()

                    self.messages['text'] = ''

                    #Partie terminée?
                    if self.partie.partie_terminee():
                        self.messages['foreground'] = 'green'
                        self.messages[
                            'text'] = 'Partie terminée, les ' + self.partie.determiner_gagnant().upper() \
                                      + ' ont gagné.\nOn recommence?!'
                except:  # Si le déplacement est invalide
                    self.piece_a_deplacer = None
                    self.position_piece_a_deplacer = None

                    # Dessin de l'echiquier
                    self.canvas_echiquier.delete('case')
                    self.canvas_echiquier.delete('piece')
                    self.canvas_echiquier.delete('select')
                    self.canvas_echiquier.dessiner_cases()
                    self.roi_en_rouge()
                    self.canvas_echiquier.dessiner_pieces()

                    self.messages['text'] = f"Le déplacement est invalide."
                    self.messages['foreground'] = 'red'

        self.messages1[
            'text'] = "Au tour du joueur: " + self.partie.joueur_actif.upper()