Beispiel #1
0
class CanvasEchiquier(Canvas):
    """Classe héritant d'un Canvas, et affichant un échiquier qui se redimensionne automatique lorsque
    la fenêtre est étirée.

    """
    def __init__(self,
                 parent,
                 n_pixels_par_case,
                 store_filename='annulerdeplacement.txt'):
        # Nombre de lignes et de colonnes.
        self.n_lignes = 8
        self.n_colonnes = 8

        # Noms des lignes et des colonnes.
        self.chiffres_rangees = ['1', '2', '3', '4', '5', '6', '7', '8']
        self.lettres_colonnes = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']

        # Nombre de pixels par case, variable.
        self.n_pixels_par_case = n_pixels_par_case

        # Appel du constructeur de la classe de base (Canvas).
        # La largeur et la hauteur sont déterminés en fonction du nombre de cases.
        super().__init__(parent,
                         width=self.n_lignes * n_pixels_par_case,
                         height=self.n_colonnes * self.n_pixels_par_case)

        # On fait en sorte que le redimensionnement du canvas redimensionne son contenu. Cet événement étant également
        # généré lors de la création de la fenêtre, nous n'avons pas à dessiner les cases et les pièces dans le
        # constructeur.
        self.bind('<Configure>', self.redimensionner)

        # Importation de Échequier et partie et Fenetre
        self.echequier = Echiquier()
        self.partie = Partie()
        self.fenetre = Fenetre

        # Dictionnaire contenant les pièces. Vous devinerez, si vous réutilisez cette classe dans votre TP4,
        # qu'il fandra adapter ce code pour plutôt utiliser la classe Echiquier.
        self.pieces = self.echequier.dictionnaire_pieces

        # Les variables nécessaires pour la fonction déplacement
        self.selectionner = 0
        self.case_source = ""
        self.case_cible = ""

        # Déterminer le gagnant
        self.gagnant_noir = False
        self.gagnant_blanc = False

        # Enregistrement des coups
        self.texte = ""

        # Fichier text annuler déplacement
        self.store_filename = os.path.join(BASE_DIR, store_filename)

        self.t = 0

    def dessiner_cases(self):
        """Méthode qui dessine les cases de l'échiquier.

        """

        for i in range(self.n_lignes):
            for j in range(self.n_colonnes):
                debut_ligne = i * self.n_pixels_par_case
                fin_ligne = debut_ligne + self.n_pixels_par_case
                debut_colonne = j * self.n_pixels_par_case
                fin_colonne = debut_colonne + self.n_pixels_par_case
                position = self.obtenir_position_a_partir_de_coordonnes(i, j)
                position_selectione = self.case_source

                # Les couleurs
                if position == position_selectione:
                    couleur = "yellow"
                elif (i + j) % 2 == 0:
                    couleur = 'white'
                else:
                    couleur = 'gray'

                # On dessine le rectangle. On utilise l'attribut "tags" pour être en mesure de récupérer les éléments
                # par la suite.
                self.create_rectangle(debut_colonne,
                                      debut_ligne,
                                      fin_colonne,
                                      fin_ligne,
                                      fill=couleur,
                                      tags='case')

    def dessiner_pieces(self):
        # Caractères unicode représentant les pièces. Vous avez besoin de la police d'écriture DejaVu.
        caracteres_pieces = {
            'PB': '\u2659',
            'PN': '\u265f',
            'TB': '\u2656',
            'TN': '\u265c',
            'CB': '\u2658',
            'CN': '\u265e',
            'FB': '\u2657',
            'FN': '\u265d',
            'RB': '\u2654',
            'RN': '\u265a',
            'DB': '\u2655',
            'DN': '\u265b'
        }

        # Pour tout paire position, pièce:

        for position, piece in self.echequier.dictionnaire_pieces.items():
            # On dessine la pièce dans le canvas, au centre de la case. On utilise l'attribut "tags" pour être en
            # mesure de récupérer les éléments dans le canvas.
            coordonnee_y = (
                self.n_lignes - self.chiffres_rangees.index(position[1]) -
                1) * self.n_pixels_par_case + self.n_pixels_par_case // 2
            coordonnee_x = self.lettres_colonnes.index(position[
                0]) * self.n_pixels_par_case + self.n_pixels_par_case // 2
            self.create_text(coordonnee_x,
                             coordonnee_y,
                             text=[piece],
                             font=('Deja Vu', self.n_pixels_par_case // 2),
                             tags='piece')

    def redimensionner(self, event):
        # Nous recevons dans le "event" la nouvelle dimension dans les attributs width et height. On veut un damier
        # carré, alors on ne conserve que la plus petite de ces deux valeurs.
        nouvelle_taille = min(event.width, event.height)

        # Calcul de la nouvelle dimension des cases.
        self.n_pixels_par_case = nouvelle_taille // self.n_lignes

        # On supprime les anciennes cases et on ajoute les nouvelles.
        self.delete('case')
        self.dessiner_cases()

        # On supprime les anciennes pièces et on ajoute les nouvelles.
        self.delete('piece')
        self.dessiner_pieces()

    def obtenir_position_a_partir_de_coordonnes(self, i, j):
        position = "{}{}".format(
            self.lettres_colonnes[j],
            int(self.chiffres_rangees[self.n_lignes - i - 1]))
        return position

    def deplacer(self, source, cible):
        self.echequier.deplacer(source, cible)
        self.rafraichir()
        self.echequier.dictionnaire_pieces.update()

    def rafraichir(self):

        # On supprimer les anciennes cases et on ajouter les nouvelles.
        self.delete("case")
        self.dessiner_cases()

        # On supprimer les anciennes pièces et on ajoute les nouvelles.
        self.delete("piece")
        self.dessiner_pieces()

    def jouer(self, event):
        x, y = event.x, event.y
        ligne = y // self.n_pixels_par_case
        colonne = x // self.n_pixels_par_case
        position = "{}{}".format(
            self.lettres_colonnes[colonne],
            int(self.chiffres_rangees[self.n_lignes - ligne - 1]))

        if self.selectionner == 1:
            self.case_cible = position

            try:

                self.deplacer(self.case_source, self.case_cible)
                if self.echequier.roi_de_couleur_est_dans_echiquier(
                        "blanc") is False:
                    messagebox.showinfo("Félicitation!",
                                        "Le joueur noir a gagné la partie!")
                    self.unbind("<Button-1>"), self.jouer
                elif self.echequier.roi_de_couleur_est_dans_echiquier(
                        "noir") is False:
                    messagebox.showinfo("Félicitation!",
                                        "Le joueur blanc a gagné la partie!")
                    self.unbind("<Button-1>"), self.jouer
                elif self.echequier.recuperer_piece_a_position(
                        self.case_source) is None:
                    self.partie.joueur_suivant()
                    self.unbind("<Button-1>"), self.jouer
                elif self.echequier.deplacement_est_valide(self.case_source, self.case_cible) is False and \
                        self.echequier.recuperer_piece_a_position(self.case_cible) is None:
                    raise DeplacementImpossible
                elif self.echequier.deplacement_est_valide(self.case_source, self.case_cible) is False and \
                        self.echequier.recuperer_piece_a_position(self.case_cible) is not None:
                    if self.echequier.couleur_piece_a_position(
                            self.case_cible
                    ) == self.echequier.couleur_piece_a_position(
                            self.case_source):
                        pass
                    else:
                        raise PriseImpossible

                self.texte += "{} {} à {} \n".format(
                    self.echequier.recuperer_piece_a_position(self.case_cible),
                    self.case_source, self.case_cible)

            except DeplacementImpossible:
                messagebox.showinfo("Erreur", "Déplacement impossible")
            except PriseImpossible:
                messagebox.showinfo("Erreur", "Prise impossible")

            self.case_source = ""
            self.case_cible = ""
            self.selectionner = 0
            self.rafraichir()

        elif self.selectionner == 0:

            try:
                if self.echequier.couleur_piece_a_position(
                        position) == self.partie.joueur_actif:
                    self.case_source = position
                    self.rafraichir()
                    self.selectionner += 1
                elif self.echequier.couleur_piece_a_position(position) != self.partie.joueur_actif and \
                        self.echequier.recuperer_piece_a_position(position) is not None:
                    raise SelectionMauvaisePiece

            except SelectionMauvaisePiece:
                messagebox.showinfo(
                    "Erreur",
                    "Selection impossible: c'est au tour du joueur {}".format(
                        self.partie.joueur_actif))

        else:
            self.selectionner = 0
            self.case_source = ""
            self.case_cible = ""

    def sauvegarder(self, filename):
        with open(filename, 'wb') as f:
            pickle.dump(self.echequier.dictionnaire_pieces, f)

    def charger(self, filename):

        with open(filename, 'rb') as f:
            data = pickle.load(f)
            f.close()
            self.echequier.dictionnaire_pieces = data
        self.rafraichir()

    def nouvelle_partie(self):
        self.echequier.initialiser_echiquier_depart()
        if self.partie.joueur_actif == "noir":
            self.partie.joueur_actif = "blanc"
        self.texte = ""
        self.rafraichir()

    def sauvegarder_mouvement(self, filename):
        with open(filename, 'wb') as f:
            pickle.dump(self.texte, f)

    def charger_mouvement(self, filename):
        with open(filename, 'rb') as f:
            data = pickle.load(f)
            f.close()
            self.texte = data
        self.rafraichir()

    def annuler_mouvement(self):
        derniere_ligne = self.texte[-9:]
        case_cible_avec = derniere_ligne[-4:]
        case_cible = case_cible_avec[0:2]
        case_source = derniere_ligne[0:3]
        self.echequier.deplacement_absolue(case_cible, case_source)
        self.rafraichir()
        self.texte = self.texte[0:-11]

    def revoir_une_partie(self, filename):
        self.nouvelle_partie()
        with open(filename, 'rb') as f:
            data = pickle.load(f)
            f.close()
            self.texte = data

        partie_en_text = self.texte
        Nombre_de_ligne = len(partie_en_text) // 11
        while Nombre_de_ligne > 0:
            ligne = partie_en_text[2:11]
            case_source = ligne[0:2]
            case_cible = ligne[-4:]
            self.echequier.deplacement_absolue(case_source, case_cible)
            Nombre_de_ligne -= 1
            partie_en_text = partie_en_text[11:]
            self.rafraichir()
            self.update()
            self.after(1500)
        pass