Esempio n. 1
0
    def deplacer(self, position_source, position_cible):
        """Effectue un déplacement de pièce si celui-ci est permis, dans l'objet echiquier et sur le canvas.

        Args:
            position_source(str):  Case de départ
            position_cible(str):  Case d'arrivée

        Returns:
            (bool):  True si le déplacement est valide et a été effectué, sinon False."""

        # Vérifier et faire le déplacement dans la source de données
        try:
            coup = Echiquier.deplacer(self, position_source, position_cible)

        # Déplacement impossible:  propager l'exception au contrôleur d'évenement
        except PychecsException as erreur:
            raise erreur

        # Sinon réfléter le changement au niveau graphique...
        else:
            # Si une prise est faite:  éliminer l'objet graphique du canvas et de la liste des objets dessinés
            if position_cible in self.dictionnaire_graphique.keys():
                self.effacer_la_piece_a_position(position_cible)

            # Mettre à jour la liste graphique et faire le déplacement sur le canvas
            self.deplacer_de_case_a_case(position_source, position_cible)

            # Si c'est un des roques, il faut aussi déplacer la tour.  Cela a été fait dans l'échiquier mais non avec
            # les objets graphiques!
            if "roque" in coup["special"]:
                couleur = self.dictionnaire_pieces[position_cible].couleur
                position_initiale, position_finale = self.parametres_du_roque(
                    couleur, coup["special"])
                self.deplacer_de_case_a_case(position_initiale,
                                             position_finale)

            # Si c'est une prise en passant, il faut éliminer un objet objet graphique pion à la case appropriée
            if coup["special"] == "en passant":
                position_prise = position_cible[0] + position_source[1]
                if position_prise in self.dictionnaire_graphique.keys():
                    self.effacer_la_piece_a_position(position_prise)

            # Si c'est une promotion, il faut remplacer le pion promu par la pièce choisie
            # Il faut aussi réévaluer si le roi est en échec, mat ou pat.
            if coup["special"] == "promotion":
                coup["special"] += self.promouvoir(position_cible)
                coup["resultat"] = self.resultat_du_coup(self.joueur_inactif())

            return coup
Esempio n. 2
0
class Partie:
    """La classe Partie contient les informations sur une partie d'échecs, c'est à dire un échiquier, puis
    un joueur actif (blanc ou noir). Des méthodes sont disponibles pour faire avancer la partie et interagir
    avec l'utilisateur.

    Attributes:
        joueur_actif (str): La couleur du joueur actif, 'blanc' ou 'noir'.
        echiquier (Echiquier): L'échiquier sur lequel se déroule la partie.

    """
    def __init__(self):
        # Le joueur débutant une partie d'échecs est le joueur blanc.
        self.joueur_actif = 'blanc'

        # Création d'une instance de la classe Echiquier, qui sera manipulée dans les méthodes de la classe.
        self.echiquier = Echiquier()

    def determiner_gagnant(self):
        """Détermine la couleur du joueur gagnant, s'il y en a un. Pour déterminer si un joueur est le gagnant,
        le roi de la couleur adverse doit être absente de l'échiquier.

        Returns:
            str: 'blanc' si le joueur blanc a gagné, 'noir' si c'est plutôt le joueur noir, et 'aucun' si aucun
                joueur n'a encore gagné.

        """

        if not self.echiquier.roi_de_couleur_est_dans_echiquier('noir'):
            return 'blanc'
        elif not self.echiquier.roi_de_couleur_est_dans_echiquier('blanc'):
            return 'noir'

        return 'aucun'

    def partie_terminee(self):
        """Vérifie si la partie est terminée. Une partie est terminée si un gagnant peut être déclaré.

        Returns:
            bool: True si la partie est terminée, et False autrement.

        """
        toutes_les_position = [
            'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'b1', 'b2', 'b3',
            'b4', 'b5', 'b6', 'b7', 'b8', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6',
            'c7', 'c8', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'e1',
            'e2', 'e3', 'e4', 'e5', 'e6', 'e7', 'e8', 'f1', 'f2', 'f3', 'f4',
            'f5', 'f6', 'f7', 'f8', 'g1', 'g2', 'g3', 'g4', 'g5', 'g6', 'g7',
            'g8', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7', 'h8'
        ]
        var = 0
        for i in toutes_les_position:
            if isinstance(
                    self.echiquier.recuperer_piece_a_position(i),
                    Pion) == True or isinstance(
                        self.echiquier.recuperer_piece_a_position(i),
                        Tour) == True or isinstance(
                            self.echiquier.recuperer_piece_a_position(i),
                            Fou) == True or isinstance(
                                self.echiquier.recuperer_piece_a_position(i),
                                Cavalier) == True or isinstance(
                                    self.echiquier.recuperer_piece_a_position(
                                        i), Dame) == True:
                var = 1
        if var == 0:
            return True
        else:
            return self.determiner_gagnant() != 'aucun'

    def demander_positions(self):
        """Demande à l'utilisateur d'entrer les positions de départ et d'arrivée pour faire un déplacement. Si les
        positions entrées sont valides (si le déplacement est valide), on retourne les deux positions. On doit
        redemander tant que l'utilisateur ne donne pas des positions valides.

        Returns:
            str, str: Deux chaînes de caractères représentant les deux positions valides fournies par l'utilisateurs.

        """
        while True:
            # On demande et valide la position source.
            while True:
                source = input("Entrez position source: ")
                if self.echiquier.position_est_valide(
                        source) and self.echiquier.couleur_piece_a_position(
                            source) == self.joueur_actif:
                    break

                print("Position invalide.\n")

            # On demande et valide la position cible.
            cible = input("Entrez position cible: ")
            if self.echiquier.deplacement_est_valide(source, cible):
                return source, cible

            print("Déplacement invalide.\n")

    def joueur_suivant(self):
        """Change le joueur actif: passe de blanc à noir, ou de noir à blanc, selon la couleur du joueur actif.

        """
        if self.joueur_actif == 'blanc':
            self.joueur_actif = 'noir'
        else:
            self.joueur_actif = 'blanc'

    def jouer(self):
        """Tant que la partie n'est pas terminée, joue la partie. À chaque tour :
            - On affiche l'échiquier.
            - On demande les deux positions.
            - On fait le déplacement sur l'échiquier.
            - On passe au joueur suivant.

        Une fois la partie terminée, on félicite le joueur gagnant!

        """
        while not self.partie_terminee():
            print(self.echiquier)
            print("\nAu tour du joueur {}".format(self.joueur_actif))
            source, cible = self.demander_positions()
            self.echiquier.deplacer(source, cible)
            self.joueur_suivant()

        print(self.echiquier)
        print("\nPartie terminée! Le joueur {} a gagné".format(
            self.determiner_gagnant()))
Esempio n. 3
0
class Partie:
    """La classe Partie contient les informations sur une partie d'échecs, c'est à dire un échiquier, puis
    un joueur actif (blanc ou noir). Des méthodes sont disponibles pour faire avancer la partie et interagir
    avec l'utilisateur.

    Attributes:
        joueur_actif (str): La couleur du joueur actif, 'blanc' ou 'noir'.
        echiquier (Echiquier): L'échiquier sur lequel se déroule la partie.

    """
    def __init__(self):
        # Le joueur débutant une partie d'échecs est le joueur blanc.
        self.joueur_actif = 'blanc'

        # Création d'une instance de la classe Echiquier, qui sera manipulée dans les méthodes de la classe.
        self.echiquier = Echiquier()

    def determiner_gagnant(self):
        """Détermine la couleur du joueur gagnant, s'il y en a un. Pour déterminer si un joueur est le gagnant,
        le roi de la couleur adverse doit être absente de l'échiquier.

        Returns:
            str: 'blanc' si le joueur blanc a gagné, 'noir' si c'est plutôt le joueur noir, et 'aucun' si aucun
                joueur n'a encore gagné.

        """
        if not self.echiquier.roi_de_couleur_est_dans_echiquier('noir'):
            return 'blanc'
        elif not self.echiquier.roi_de_couleur_est_dans_echiquier('blanc'):
            return 'noir'

        return 'aucun'

    def partie_terminee(self):
        """Vérifie si la partie est terminée. Une partie est terminée si un gagnant peut être déclaré.

        Returns:
            bool: True si la partie est terminée, et False autrement.

        """
        return self.determiner_gagnant() != 'aucun'

    def demander_positions(self):
        """Demande à l'utilisateur d'entrer les positions de départ et d'arrivée pour faire un déplacement. Si les
        positions entrées sont valides (si le déplacement est valide), on retourne les deux positions. On doit
        redemander tant que l'utilisateur ne donne pas des positions valides.

        Returns:
            str, str: Deux chaînes de caractères représentant les deux positions valides fournies par l'utilisateurs.

        """
        while True:
            # On demande et valide la position source.
            while True:
                source = input("Entrez position source: ")
                if self.echiquier.position_est_valide(
                        source) and self.echiquier.couleur_piece_a_position(
                            source) == self.joueur_actif:
                    break

                print("Position invalide.\n")

            # On demande et valide la position cible.
            cible = input("Entrez position cible: ")
            if self.echiquier.deplacement_est_valide(source, cible):
                return source, cible

            print("Déplacement invalide.\n")

    def deplacer(self, position_source, position_cible):

        piece = self.echiquier.recuperer_piece_a_position(position_source)
        print("la piece est", piece)

        if piece is None:

            raise AucunePieceAPosition('Aucune pièce à cet emplacement')
        elif piece.couleur != self.joueur_actif:
            raise MauvaiseCouleurPiece(
                "La pièce source n'appartient pas au joueur actif")

        self.echiquier.deplacer(position_source, position_cible)
        self.joueur_suivant()

    def joueur_suivant(self):
        """Change le joueur actif: passe de blanc à noir, ou de noir à blanc, selon la couleur du joueur actif.

        """
        if self.joueur_actif == 'blanc':
            self.joueur_actif = 'noir'

        else:
            self.joueur_actif = 'blanc'

    def jouer(self):
        """Tant que la partie n'est pas terminée, joue la partie. À chaque tour :
            - On affiche l'échiquier.
            - On demande les deux positions.
            - On fait le déplacement sur l'échiquier.
            - On passe au joueur suivant.

        Une fois la partie terminée, on félicite le joueur gagnant!

        """
        while not self.partie_terminee():
            print(self.echiquier)
            print("\nAu tour du joueur {}".format(self.joueur_actif))
            source, cible = self.demander_positions()
            self.echiquier.deplacer(source, cible)
            self.joueur_suivant()

        print(self.echiquier)
        print("\nPartie terminée! Le joueur {} a gagné".format(
            self.determiner_gagnant()))
Esempio n. 4
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
Esempio n. 5
0
class Partie:
    """La classe Partie contient les informations sur une partie d'échecs, c'est à dire un échiquier, puis
    un joueur actif (blanc ou noir). Des méthodes sont disponibles pour faire avancer la partie et interagir
    avec l'utilisateur.

    Attributes:
        joueur_actif (str): La couleur du joueur actif, 'blanc' ou 'noir'.
        echiquier (Echiquier): L'échiquier sur lequel se déroule la partie.

    """
    def __init__(self):
        # Le joueur débutant une partie d'échecs est le joueur blanc.
        self.joueur_actif = 'blanc'

        # Création d'une instance de la classe Echiquier, qui sera manipulée dans les méthodes de la classe.
        self.echiquier = Echiquier()

    def determiner_gagnant(self):
        """Détermine la couleur du joueur gagnant, s'il y en a un. Pour déterminer si un joueur est le gagnant,
        le roi de la couleur adverse doit être absente de l'échiquier.

        Returns:
            str: 'blanc' si le joueur blanc a gagné, 'noir' si c'est plutôt le joueur noir, et 'aucun' si aucun
                joueur n'a encore gagné.

        """
        if not self.echiquier.roi_de_couleur_est_dans_echiquier('noir'):
            return 'blanc'
        elif not self.echiquier.roi_de_couleur_est_dans_echiquier('blanc'):
            return 'noir'

        return 'aucun'

    def partie_terminee(self):
        """Vérifie si la partie est terminée. Une partie est terminée si un gagnant peut être déclaré.

        Returns:
            bool: True si la partie est terminée, et False autrement.

        """
        return self.determiner_gagnant() != 'aucun'

    def demander_positions(self):
        """Demande à l'utilisateur d'entrer les positions de départ et d'arrivée pour faire un déplacement. Si les
        positions entrées sont valides (si le déplacement est valide), on retourne les deux positions. On doit
        redemander tant que l'utilisateur ne donne pas des positions valides.

        Returns:
            str, str: Deux chaînes de caractères représentant les deux positions valides fournies par l'utilisateurs.

        """
        while True:
            # On demande et valide la position source.
            while True:
                source = input("Entrez position source: ")
                if self.echiquier.position_est_valide(source) and self.echiquier.couleur_piece_a_position(source) == self.joueur_actif:
                    break

                print("Position invalide.\n")

            # On demande et valide la position cible.
            cible = input("Entrez position cible: ")
            if self.echiquier.deplacement_est_valide(source, cible):
                return source, cible

            print("Déplacement invalide.\n")

    def joueur_suivant(self):
        """Change le joueur actif: passe de blanc à noir, ou de noir à blanc, selon la couleur du joueur actif.

        """
        if self.joueur_actif == 'blanc':
            self.joueur_actif = 'noir'
        else:
            self.joueur_actif = 'blanc'

    def jouer(self):
        """Tant que la partie n'est pas terminée, joue la partie. À chaque tour :
            - On affiche l'échiquier.
            - On demande les deux positions.
            - On fait le déplacement sur l'échiquier.
            - On passe au joueur suivant.

        Une fois la partie terminée, on félicite le joueur gagnant!

        """
        while not self.partie_terminee():
            print(self.echiquier)
            print("\nAu tour du joueur {}".format(self.joueur_actif))
            source, cible = self.demander_positions()
            self.echiquier.deplacer(source, cible)
            self.joueur_suivant()

        print(self.echiquier)
        print("\nPartie terminée! Le joueur {} a gagné".format(self.determiner_gagnant()))
class Partie:
    """La classe Partie contient les informations sur une partie d'échecs, c'est à dire un échiquier, puis
    un joueur actif (blanc ou noir). Des méthodes sont disponibles pour faire avancer la partie et interagir
    avec l'utilisateur.

    Attributes:
        joueur_actif (str): La couleur du joueur actif, 'blanc' ou 'noir'.
        echiquier (Echiquier): L'échiquier sur lequel se déroule la partie.

    """
    def __init__(self):
        # Le joueur débutant une partie d'échecs est le joueur blanc.
        self.joueur_actif = 'blanc'

        # Création d'une instance de la classe Echiquier, qui sera manipulée dans les méthodes de la classe.
        self.echiquier = Echiquier()

    def determiner_gagnant(self):
        """Détermine la couleur du joueur gagnant, s'il y en a un. Pour déterminer si un joueur est le gagnant,
        le roi de la couleur adverse doit être absente de l'échiquier.

        Returns:
            str: 'blanc' si le joueur blanc a gagné, 'noir' si c'est plutôt le joueur noir, et 'aucun' si aucun
                joueur n'a encore gagné.

        """
        #Cas où le roi noir est absent de l'échiquier.
        if not self.echiquier.roi_de_couleur_est_dans_echiquier('noir'):
            return 'blanc'

        #Cas où le roi blanc est absent de l'échiquier.
        if not self.echiquier.roi_de_couleur_est_dans_echiquier('blanc'):
            return 'noir'

        #Cas où les deux rois sont sur l'échiquier.
        return 'aucun'

    def partie_terminee(self):
        """Vérifie si la partie est terminée. Une partie est terminée si un gagnant peut être déclaré.

        Returns:
            bool: True si la partie est terminée, et False autrement.

        """
        #Cas où le joueur blanc ou le joueur noir est le gagnant.
        if self.determiner_gagnant() == 'blanc' or self.determiner_gagnant() == 'noir':
            return True

        #Cas où il n'y a encore aucun gagnant.
        return False

    def piece_position_depart(self,position_depart):
        """
        Détermine si la position de départ donner par l'utilisateur est sur l'échiquier.
        On vérifie qu'il y a bien une pièce du joueur actif sur cette case.
        S'il n'y a pas de pièce ou que c'est la pièce d'un autre joueur on retourne un message d'erreur.
        :param position_depart:
            str: Une chaine de charactère qui représente une position à évaluer.
        :return:
            bool: True si le la position est valide et a une pièce du joueur actif, et False autrement.
        """
        #On redemande la position de départ tant que la position n'est pas valide.
        if not self.echiquier.position_est_valide(position_depart):
            return False

        #Tant qu'il n'y a pas de pièces on informe le joueur qu'il ne peux pas choisir cette case de départ et on redemande la position de départ
        if self.echiquier.recuperer_piece_a_position(position_depart) is None:
            print("Il n'y a pas de pièce sur cette case")
            return False
        #Tant que ce n'est pas une de ses pièces on informe le joueur qu'il ne peut pas jouer cette pièce et on redemande la position de départ.
        if self.echiquier.couleur_piece_a_position(position_depart) != self.joueur_actif:
            print("Vous jouer les pieces de l'autre joueur, TRICHEUR!")
            return False
        # Si c'est une bonne position, avec un pièce du joueur actif on retourne true.
        return True

    def demander_positions(self):
        """Demande à l'utilisateur d'entrer les positions de départ et d'arrivée pour faire un déplacement. Si les
        positions entrées sont valides (si le déplacement est valide), on retourne les deux positions. On doit
        redemander tant que l'utilisateur ne donne pas des positions valides.

        Returns:
            str, str: Deux chaînes de caractères représentant les deux positions valides fournies par l'utilisateurs.

        """
        #On demande la position de départ au joueur.
        position_depart = fenetre.selectionner_pièce()

        #On redemande la position de départ tant que la position n'est pas une position avec une pièce du joueur.
        while not self.piece_position_depart(position_depart):
                    position_depart = fenetre.selectionner_pièce()

        #On demande la position d'arriver au joueur.
        position_arrive = fenetre.selectionner_arriver()

        #On redemande la position d'arriver tant que la position n'est pas valide.
        while not self.echiquier.position_est_valide(position_arrive):
            position_arrive = fenetre.selectionner_arriver()

        #retourne les positions de départ et d'arriver.
        return position_depart, position_arrive

    def joueur_suivant(self):
        """Change le joueur actif: passe de blanc à noir, ou de noir à blanc, selon la couleur du joueur actif.

        """
        # Si le joueur actif est blanc on le change en noir
        if self.joueur_actif == 'blanc':
            self.joueur_actif = 'noir'

        #Si le joueur actif est noir on le change en blanc
        elif self.joueur_actif == 'noir':
            self.joueur_actif = 'blanc'

    def jouer(self):
        """Tant que la partie n'est pas terminée, joue la partie. À chaque tour :
            - On affiche l'échiquier.
            - On demande les deux positions.
            - On fait le déplacement sur l'échiquier.
            - On passe au joueur suivant.

        Une fois la partie terminée, on félicite le joueur gagnant!

        """


        partie_est_terminer = False

        #On forme une boucle de jeu qui va continuer tant que la partie n'est pas terminer.
        while not partie_est_terminer:

            #On affiche l'échiquier.
            f = fenetre()

            #On informe quel est la couleur du joueur actif.
            print("C'est au tour du joueur:",self.joueur_actif)

            deplacement_valide = False

            #On forme une seconde boucle qui va continuer tant qu'on n'entre pas un déplacement valide.
            while not deplacement_valide:

                #On demande à l'utilisateur les positions de départ et d'arriver du déplacement.
                while position_depart is None:
                    position_depart = fenetre.selectionner_pièce
                if position_depart is not None:
                    while position_arrive is None:
                        position_arrive = fenetre.selectionner_arriver

                #Maintenant qu'on a une position de départ et d'arriver,on vérifie que c'est un déplacement valide.
                deplacement_valide = self.echiquier.deplacer(position_depart,position_arrive)

            #On verifie si la partie est terminé.
            partie_est_terminer = self.partie_terminee()
            #Si c'est le cas on félicite le joueur gagnant.
            if partie_est_terminer:
                print("Bravo joueur", self.joueur_actif,"vous avez gagné!")

            #S'il n'y a pas de gagnant, la partie n'est pas fini, on change de joueur actif.
            else:
                self.joueur_suivant()
        f.mainloop()
Esempio n. 7
0
class Partie:
    """
    La classe Partie contient les informations sur une partie d'échecs, c'est à dire un échiquier, puis
    un joueur actif (blanc ou noir). Des méthodes sont disponibles pour faire avancer la partie et interagir
    avec l'utilisateur.

    Attributes:
        joueur_actif (str): La couleur du joueur actif, 'blanc' ou 'noir'.
        echiquier (Echiquier): L'échiquier sur lequel se déroule la partie.
    """
    def __init__(self):
        # Le joueur débutant une partie d'échecs est le joueur blanc.
        self.joueur_actif = 'blanc'

        # Création d'une instance de la classe Echiquier, qui sera manipulée dans les méthodes de la classe.
        self.echiquier = Echiquier()

        #intialisation de deux listes qui permettront d'afficher les derniers déplacements
        self.listeDeplacements = []
        self.dernierDeplacement = []

        self.hist = []

        self.nom_fichier_sauvegarde = 'sauvegarde'

    def determiner_gagnant(self):
        """Détermine la couleur du joueur gagnant, s'il y en a un. Pour déterminer si un joueur est le gagnant,
        le roi de la couleur adverse doit être absente de l'échiquier.

        Returns:
            str: 'blanc' si le joueur blanc a gagné, 'noir' si c'est plutôt le joueur noir, et 'aucun' si aucun
                joueur n'a encore gagné.

        """
        if not self.echiquier.roi_de_couleur_est_dans_echiquier('noir'):
            return 'blanc'
        elif not self.echiquier.roi_de_couleur_est_dans_echiquier('blanc'):
            return 'noir'

        return 'aucun'

    def partie_terminee(self):
        """Vérifie si la partie est terminée. Une partie est terminée si un gagnant peut être déclaré.

        Returns:
            bool: True si la partie est terminée, et False autrement.

        """
        return self.determiner_gagnant() != 'aucun'

    def annulerDernierMouvement(self):
        """
        Permet d'annuler le dernier mouvement et de rafraichir les pieces blanches et noires qui restent.
        Un premier scénario ou la liste a 2 ou moins historique d'échiquier.
        Un deuxième scénario dans le cas contraire.
        """

        if len(self.echiquier.listeDesEchiquiers) <= 2:
            self.echiquier.initialiser_echiquier_depart()
            self.joueur_actif = 'blanc'

        else:
            del self.echiquier.listeDesEchiquiers[-1]
            self.echiquier.dictionnaire_pieces = self.echiquier.listeDesEchiquiers[
                -1]
            self.joueur_suivant()

        self.resteBlanc = set()
        self.resteNoir = set()
        for i in self.echiquier.dictionnaire_pieces.values():
            if i.est_blanc():
                self.resteBlanc.add(i)
            else:
                self.resteNoir.add(i)
        self.gapBlanc = list(self.echiquier.setBlanc - self.resteBlanc)
        self.gapNoir = list(self.echiquier.setNoir - self.resteNoir)

    def roque_est_valide(self, position_source, position_cible):
        """
            Identifie si le Roi peut effectuer un Roque.
            Pour pouvoir effectuer un Roque, il faut que:
            1. La pièece à la position_cible soit une Tour
            2. La pièce à la position_source soit un Roi
            3. Ni le Roi ni la Tour n'aient effectué de mouvement depuis le début de la partie.
            4. La voie doit être libre (aucune pièce) entre le Roi et la Tour.
            5. Aucune case entre le Roi et la Tour ne soit menacée par l'adversaire.
            6. Le roi ne soit pas en échec.
            7. La tour ne soit pas menacée.

            Args:
                position_source (str): Position du Roi
                position_cible (str): Position de la Tour

            Returns:
                bool: True si le Roi peut Roquer, et False autrement.
        """
        couleur_adversaire = 'blanc'
        rangee_origine = '8'

        piece = self.echiquier.recuperer_piece_a_position(position_source)
        piece_cible = self.echiquier.recuperer_piece_a_position(position_cible)

        if piece.couleur == 'blanc':
            couleur_adversaire = 'noir'
            rangee_origine = '1'
        #critères de 1 à 3
        if isinstance(piece, Roi) and isinstance(piece_cible, Tour) and\
                piece.couleur == piece_cible.couleur and\
                self.echiquier.recuperer_piece_a_position(position_source) not in self.hist and \
                self.echiquier.recuperer_piece_a_position(position_cible) not in self.hist:
            if position_cible[0] == 'a':  #Grand Roque
                for colonne in self.echiquier.lettres_colonnes[0:5]:
                    #critères 5 à 7
                    if self.echiquier.case_est_menacee_par(
                            colonne + rangee_origine, couleur_adversaire):
                        return False
                return True
            else:  #Petit Roque
                for colonne in self.echiquier.lettres_colonnes[4:]:
                    # critères 5 à 7
                    if self.echiquier.case_est_menacee_par(
                            colonne + rangee_origine, couleur_adversaire):
                        return False
                return True

    def roquer(self, position_source, position_cible):
        """
            Effectue le mouvement de Roque si celui-ce est valide dans l'échiquier.

            Args:
                position_source (str): position du Roi dans l'échiquier
                position_cible (str): position de la Tour dans l'échiquier.
        """

        self.joueur_suivant()
        if ord(position_source[0]) > ord(position_cible[0]):
            position_roi = 'c' + position_source[1]
            self.echiquier.dictionnaire_pieces[position_roi] = \
                self.echiquier.recuperer_piece_a_position(position_source)
            del self.echiquier.dictionnaire_pieces[position_source]

            position_tour = 'd' + position_cible[1]
            self.echiquier.dictionnaire_pieces[position_tour] = \
                self.echiquier.recuperer_piece_a_position(position_cible)
            del self.echiquier.dictionnaire_pieces[position_cible]
        else:
            position_roi = 'g' + position_source[1]
            self.echiquier.dictionnaire_pieces[position_roi] = \
                self.echiquier.recuperer_piece_a_position(position_source)
            del self.echiquier.dictionnaire_pieces[position_source]

            position_tour = 'f' + position_cible[1]
            self.echiquier.dictionnaire_pieces[position_tour] = \
                self.echiquier.recuperer_piece_a_position(position_cible)
            del self.echiquier.dictionnaire_pieces[position_cible]

        #Trucs a Thierry
        piece = self.echiquier.recuperer_piece_a_position(position_source)
        self.dernierDeplacement = [
            "(" + self.joueur_actif + ")" + position_source + "->" +
            position_cible
        ]
        self.listeDeplacements.append(self.dernierDeplacement)

        echiquierCopy = dict(self.echiquier.dictionnaire_pieces)
        self.echiquier.listeDesEchiquiers.append(echiquierCopy)

        self.resteBlanc = set()
        self.resteNoir = set()
        for i in self.echiquier.dictionnaire_pieces.values():
            if (i.est_blanc()):
                self.resteBlanc.add(i)
            else:
                self.resteNoir.add(i)

        self.gapBlanc = list(self.echiquier.setBlanc - self.resteBlanc)
        self.gapNoir = list(self.echiquier.setNoir - self.resteNoir)

    def deplacer(self, position_source, position_cible):
        """
            Permet de d'appeler le mouvement à la méthode déplacer du module Échiquier.
            Permet aussi de recalculer les pièces mangées qui sert dans le visuel du jeux.
            En même temps, sert à écrire ce qui sera communiquer au joueur sur la liste des déplacements
            dans le Listbox du jeux.

            Args:
                position_source (str): Position de source de la pièce
                position_cible (str): Position cible de la pièce

        """
        piece = self.echiquier.recuperer_piece_a_position(position_source)

        #Pour le roque
        if self.echiquier.deplacement_est_valide(position_source,
                                                 position_cible):
            self.hist.append(piece)

        self.echiquier.deplacer(position_source, position_cible)

        self.joueur_suivant()
        self.dernierDeplacement = [
            "(" + piece.couleur + ")" + position_source + "->" + position_cible
        ]
        self.listeDeplacements.append(self.dernierDeplacement)

        echiquierCopy = dict(self.echiquier.dictionnaire_pieces)
        self.echiquier.listeDesEchiquiers.append(echiquierCopy)

        self.dictionnaire_pieces_initial = {
            'a1': Tour('blanc'),
            'b1': Cavalier('blanc'),
            'c1': Fou('blanc'),
            'd1': Dame('blanc'),
            'e1': Roi('blanc'),
            'f1': Fou('blanc'),
            'g1': Cavalier('blanc'),
            'h1': Tour('blanc'),
            'a2': Pion('blanc'),
            'b2': Pion('blanc'),
            'c2': Pion('blanc'),
            'd2': Pion('blanc'),
            'e2': Pion('blanc'),
            'f2': Pion('blanc'),
            'g2': Pion('blanc'),
            'h2': Pion('blanc'),
            'a7': Pion('noir'),
            'b7': Pion('noir'),
            'c7': Pion('noir'),
            'd7': Pion('noir'),
            'e7': Pion('noir'),
            'f7': Pion('noir'),
            'g7': Pion('noir'),
            'h7': Pion('noir'),
            'a8': Tour('noir'),
            'b8': Cavalier('noir'),
            'c8': Fou('noir'),
            'd8': Dame('noir'),
            'e8': Roi('noir'),
            'f8': Fou('noir'),
            'g8': Cavalier('noir'),
            'h8': Tour('noir'),
        }

        self.setBlanc = set()
        self.setNoir = set()
        for i in self.dictionnaire_pieces_initial.values():
            if i.est_blanc():
                self.setBlanc.add(i)
            else:
                self.setNoir.add(i)

        self.resteBlanc = set()
        self.resteNoir = set()
        for i in self.echiquier.dictionnaire_pieces.values():
            if i.est_blanc():
                self.resteBlanc.add(i)
            else:
                self.resteNoir.add(i)

        self.gapBlanc = list(self.echiquier.setBlanc - self.resteBlanc)
        self.gapNoir = list(self.echiquier.setNoir - self.resteNoir)

    def joueur_suivant(self):
        """Change le joueur actif: passe de blanc à noir, ou de noir à blanc, selon la couleur du joueur actif.

        """
        if self.joueur_actif == 'blanc':
            self.joueur_actif = 'noir'
        else:
            self.joueur_actif = 'blanc'

    def position_mon_roi(self, couleur_joueur_actif):
        """
            Identifie ou se trouve le roi de la couleur entrée en argument dans l'échiquier.

            Args:
                couleur_joueur_actif (str): couleur du joueur dont on souhaite connaître la position du Roi.
            Returns:
                str: Retourne la position du roi dans l'échiquier.
        """
        for position in self.echiquier.dictionnaire_pieces.keys():
            if isinstance(self.echiquier.dictionnaire_pieces[position], Roi) \
                    and self.echiquier.dictionnaire_pieces[position].couleur == couleur_joueur_actif:
                return position

    def mon_roi_en_echec(self):
        """
            Identifie si le Roi du joueur actif est en échec.
            Par en échec on entend que sa case est menacée par le joueur adverse.
            Si le joueur actif ne réagit pas à la menace, il perdra la partie au prochain tour.

            Returns:
                bool: True si le Roi du joueur actif est en échec, false autrement.
        """
        position_roi = self.position_mon_roi(self.joueur_actif)
        if self.joueur_actif == 'blanc':
            autre_couleur = 'noir'
        else:
            autre_couleur = 'blanc'

        if self.partie_terminee():
            return False
        return self.echiquier.case_est_menacee_par(position_roi, autre_couleur)

    def sauvegarder_partie(self):
        """
        Permet de sauver la partie.
        """
        with open(self.nom_fichier_sauvegarde, "wb") as f:
            pickle.dump(self.echiquier.dictionnaire_pieces, f)

    def charger_partie(self):
        """
        Permet de charger une partie sauvegarder avec la méthode sauvergarder_partie
        """
        with open(self.nom_fichier_sauvegarde, "rb") as f:
            self.echiquier.dictionnaire_pieces = pickle.load(f)