Esempio n. 1
0
    def __init__(self, nom_fichier=None):
        """
        Méthode d'initialisation d'une partie. On initialise 4 membres:
        - planche: contient la planche de la partie, celui-ci contenant le dictionnaire de pièces.
        - couleur_joueur_courant: le joueur à qui c'est le tour de jouer.
        - tour_precedent_passe: un booléen représentant si le joueur précédent a passé son tour parce qu'il
           n'avait aucun coup disponible.
        - deux_tours_passes: un booléen représentant si deux tours ont été passés de suite, auquel cas la partie
           devra se terminer.
        - coups_possibles : une liste de tous les coups possibles en fonction de l'état actuel de la planche,
           initialement vide.

        On initialise ensuite les joueurs selon la paramètre nom_fichier. Si l'utilisateur a précisé un nom_fichier,
        on fait appel à la méthode self.charger() pour charger la partie à partir d'un fichier. Sinon, on fait appel
        à self.initialiser_joueurs(), qui va demander à l'utilisateur quels sont les types de joueurs qu'il désire.
        """
        self.planche = Planche()

        self.couleur_joueur_courant = "noir"

        self.tour_precedent_passe = False

        self.deux_tours_passes = False

        self.coups_possibles = []

        if nom_fichier is not None:
            self.charger(nom_fichier)
        else:
            self.initialiser_joueurs()
Esempio n. 2
0
    def __init__(self):
        self.planche = Planche()

        self.couleur_joueur_courant = "noir"

        self.tour_precedent_passe = False

        self.deux_tours_passes = False

        self.coups_possibles = []

        self.initialiser_joueurs()
    def __init__(self):
        super().__init__()
        self.planche = Planche()
        self.partie = Partie()

        # decommenter si on veut charger une partie et inserer le nom du fichier texte.

        #self.partie = Partie('partie_un_tour_a_passer.txt')

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

        # La position sélectionnée.
        self.position_selectionnee = None

        # 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_planche.
        self.canvas_planche = CanvasPlanche(self, 60)
        self.canvas_planche.grid(sticky=NSEW)

        # Ajout d'une étiquette d'information.
        self.messages = Label(self)
        self.messages.grid()

        # On lie un clic sur canvas_planche à une méthode.
        self.canvas_planche.bind('<Button-1>', self.selectionner)
        self.canvas_planche.pieces = self.convertir_case_a_piece()
Esempio n. 4
0
class Partie:
    """
     Définition de la classe Partie qui englobe la planche, l'IA, les pièces,
     les joueurs et détermine les coups possibles
    """
    def __init__(self,
                 nb_joueurs: int,
                 difficulte: str,
                 nb_cases: int,
                 nom_fichier=None):
        """
        Méthode d'initialisation d'une partie. On initialise 4 membres:
        - planche: contient la planche de la partie, celui-ci contenant le
          dictionnaire de pièces.
        - couleur_joueur_courant: le joueur à qui c'est le tour de jouer.
        - tour_precedent_passe: un booléen représentant si le joueur précédent
          a passé son tour parce qu'il n'avait aucun coup disponible.
        - deux_tours_passes: un booléen représentant si deux tours ont été
          passés de suite, auquel cas la partie
           devra se terminer.
        - coups_possibles : une liste de tous les coups possibles en fonction
          de l'état actuel de la planche, initialement vide.
        - intelligenceartificielle: classe contenant les méthodes d'analyse de
          partie de l'IA

        On initialise ensuite les joueurs selon la paramètre nom_fichier. Si
        l'utilisateur a précisé un nom_fichier, on fait appel à la méthode
        self.charger() pour charger la partie à partir d'un fichier. Sinon, on
        fait appel à self.initialiser_joueurs(), qui va demander à
        l'utilisateur quels sont les types de joueurs qu'il désire.
        """

        self.difficulte = difficulte
        self.nb_cases = nb_cases
        self.planche = Planche(self.nb_cases)
        self.nb_joueurs = nb_joueurs

        self.couleur_joueur_courant = "noir"

        self.tour_precedent_passe = False

        self.deux_tours_passes = False

        self.coups_possibles = []

        if nom_fichier is None:
            self.initialiser_joueurs()

        self.coups_du_tour = self.planche.lister_coups_possibles_de_couleur(
            self.joueur_courant.couleur)
        self.coups_possibles = self.coups_du_tour[0]

    def initialiser_joueurs(self):
        """
        On initialise ici trois attributs : joueur_noir, joueur_blanc et
        joueur_courant (initialisé à joueur_noir).

        Pour créer les objets joueur, faites appel à demander_type_joueur()
        """

        self.joueur_noir = self.creer_joueur("Humain", "noir")
        if self.nb_joueurs == 1:
            self.joueur_blanc = self.creer_joueur("Ordinateur", "blanc")
        elif self.nb_joueurs == 2:
            self.joueur_blanc = self.creer_joueur("Huamin", "blanc")
        self.joueur_courant = self.joueur_noir

    @staticmethod
    def creer_joueur(typejoueur: str, couleur: str):
        """
        Crée l'objet Joueur approprié, selon le type passé en paramètre.

        Args:
            typejoueur: le type de joueur, "Ordinateur" ou "Humain"
            couleur: la couleur du pion joué par le jouer, "blanc" ou "noir"

        Returns:
            Un objet JoueurHumain si le type est "Humain", JoueurOrdinateur
            sinon
        """

        if typejoueur == "Ordinateur":
            joueur = JoueurOrdinateur(couleur)
        else:
            joueur = JoueurHumain(couleur)

        return joueur

    def tour(self, coup_clic: tuple):
        """
        Cette méthode simule le tour d'un joueur, et effectue les actions
         suivantes:
        - Si le joueur courant est un Ordinateur, lui demande le coup qu'il
          veut effecteur avec demander_coup()
        - S'il s'agit d'un joueur humain, utilise le paramètre coup_clic pour
          effectuer son coup sur la planche
        - Joue le coup sur la planche de jeu, avec la bonne couleur.

        :param coup_clic: tuple de la position cliquée par le joueur sur le GUI

        :returns: La position jouée par le joueur
        """

        if self.joueur_courant.obtenir_type_joueur() == "Humain":
            coup_demander = coup_clic
            self.planche.jouer_coup(coup_demander, self.joueur_courant.couleur)
        else:
            coup_demander = self.demander_coup((-1, -1))
            self.planche.jouer_coup(coup_demander, "blanc")  # Ordi jamais noir
        return coup_demander

    def demander_coup(self, coup_clic: tuple):
        """
        Demande au joueur courant le coup qu'il souhaite jouer. Si le joueur
        courant est un humain, on appelle directement
        self.joueur_courant.choisir_coup() pour ce faire. S'il s'agit d'un
        ordinateur, on commence par filtrer les meilleurs coups avec
        self.intelligenceartificielle.filtrer_meilleurs_coups() avant de faire
        choisir coup.

        :returns coup_choisi: un couple positionnel sous forme de tuple
            représentant le coup demandé par le joueur.
        """

        if self.joueur_courant.obtenir_type_joueur() == "Humain":
            coup_choisi = coup_clic
        else:
            if self.difficulte == "legendaire":
                self.intelligenceartificielle = IALegendaire(
                    self.planche.nb_cases, self.planche.cases,
                    self.couleur_joueur_courant)
            elif self.difficulte == "difficile":
                self.intelligenceartificielle = IADifficile(
                    self.planche.nb_cases, self.planche.cases,
                    self.couleur_joueur_courant)
            elif self.difficulte == "normale":
                self.intelligenceartificielle = IANormale(
                    self.planche.nb_cases, self.planche.cases,
                    self.couleur_joueur_courant)
            else:  # Facile = random
                coup_choisi = self.joueur_courant.choisir_coup(
                    self.coups_possibles)
                return coup_choisi
            coups_ia = self.intelligenceartificielle.\
                filtrer_meilleurs_coups()
            coup_choisi = self.joueur_courant.choisir_coup(coups_ia)
        return coup_choisi

    def partie_terminee(self):
        """
        Détermine si la partie est terminée, Une partie est terminée si toutes
        les cases de la planche sont remplies ou si deux tours consécutifs ont
        été passés.

        :returns: True si terminée, False sinon
        """

        if self.deux_tours_passes:
            return True
        elif len(self.planche.cases) == self.planche.nb_cases**2:
            return True
        else:
            return False

    def determiner_gagnant(self):
        """
        Détermine le gagnant de la partie. Le gagnant est simplement la couleur
        pour laquelle il y a le plus de pions sur la planche de jeu.

        :returns tuple: Tuple d'un bool et d'un str
                    bool: indique (True) si humain a gagné ou non (False)
                    str: Message contenant les informations sur le gagnant,
                             ou de partie nulle
        """

        pieces_noires = 0
        pieces_blanches = 0

        # Compte les pièces de chaque couleur
        for case in self.planche.liste_cases:
            if self.planche.get_piece(case):
                if self.planche.get_piece(case).couleur == "blanc":
                    pieces_blanches += 1
                elif self.planche.get_piece(case).couleur == "noir":
                    pieces_noires += 1
Esempio n. 5
0
from othello.planche import Planche
from othello.planche import Piece
import ast

planche_de_jeu = Planche()
print(planche_de_jeu)

for col in planche_de_jeu.cases.values():
    print(col.est_noir())

# planche_de_jeu.jouer_coup((5,4), "noir")
# print(planche_de_jeu)

# chaine = planche_de_jeu.convertir_en_chaine()
# print(chaine)
# chaine_en_liste = chaine.split("\n")[:-1]
# print(chaine_en_liste)
# print(chaine_en_liste[0][4:])
# compteur_blanc = 0
# compteur_noir = 0
# i = 0
# while i <= len(chaine_en_liste) - 1:
#     if chaine_en_liste[i][4:] == "noir":
#         compteur_noir += 1
#     elif chaine_en_liste[i][4:] == "blanc":
#         compteur_blanc += 1
#     i += 1
# print(compteur_blanc)
# print(compteur_noir)

# x = 3, 5, 5
Esempio n. 6
0
class Partie:
    def __init__(self, nom_fichier=None):
        """
        Méthode d'initialisation d'une partie. On initialise 4 membres:
        - planche: contient la planche de la partie, celui-ci contenant le dictionnaire de pièces.
        - couleur_joueur_courant: le joueur à qui c'est le tour de jouer.
        - tour_precedent_passe: un booléen représentant si le joueur précédent a passé son tour parce qu'il
           n'avait aucun coup disponible.
        - deux_tours_passes: un booléen représentant si deux tours ont été passés de suite, auquel cas la partie
           devra se terminer.
        - coups_possibles : une liste de tous les coups possibles en fonction de l'état actuel de la planche,
           initialement vide.

        On initialise ensuite les joueurs selon la paramètre nom_fichier. Si l'utilisateur a précisé un nom_fichier,
        on fait appel à la méthode self.charger() pour charger la partie à partir d'un fichier. Sinon, on fait appel
        à self.initialiser_joueurs(), qui va demander à l'utilisateur quels sont les types de joueurs qu'il désire.
        """
        self.planche = Planche()

        self.couleur_joueur_courant = "noir"

        self.tour_precedent_passe = False

        self.deux_tours_passes = False

        self.coups_possibles = []

        if nom_fichier is not None:
            self.charger(nom_fichier)
        else:
            self.initialiser_joueurs()

    def initialiser_joueurs(self):
        """
        On initialise ici trois attributs : joueur_noir, joueur_blanc et joueur_courant (initialisé à joueur_noir).

        Pour créer les objets joueur, faites appel à demander_type_joueur()
        """
        self.joueur_noir = self.demander_type_joueur("noir")
        self.joueur_blanc = self.demander_type_joueur("blanc")
        self.joueur_courant = self.joueur_noir

    def demander_type_joueur(self, couleur):
        """
        Demande à l'usager quel type de joueur ('Humain' ou 'Ordinateur') il désire pour le joueur de la couleur.

        Tant que l'entrée n'est pas valide, on continue de demander à l'utilisateur.

        Faites appel à self.creer_joueur() pour créer le joueur lorsque vous aurez le type.

        Args:
            couleur: La couleur pour laquelle on veut le type de joueur.

        Returns:
            Un objet Joueur, de type JoueurHumain si l'usager a entré 'Humain', JoueurOrdinateur s'il a entré
            'Ordinateur'.
        """
        type_desire = input("""Quel type de joueur désirez vous associé à la couleur ({}) ? Les choix possibles sont: 
        "Humain" ou "Ordinateur" """.format(couleur))

        if type_desire == "Humain" or type_desire == "Ordinateur":
            return self.creer_joueur(type_desire, couleur)

        else:
            self.demander_type_joueur(couleur)


    def creer_joueur(self, type, couleur):
        """
        Crée l'objet Joueur approprié, selon le type passé en paramètre.

        Pour créer les objets, vous n'avez qu'à faire appel à leurs constructeurs, c'est-à-dire à
        JouerHumain(couleur), par exemple.

        Args:
            type: le type de joueur, "Ordinateur" ou "Humain"
            couleur: la couleur du pion joué par le jouer, "blanc" ou "noir"

        Returns:
            Un objet JoueurHumain si le type est "Humain", JoueurOrdinateur sinon
        """
        if type == "Humain":
            joueur_cree = JoueurHumain(couleur)

        else:
            joueur_cree = JoueurOrdinateur(couleur)

        return joueur_cree

    def valider_position_coup(self, position_coup):
        """
        Vérifie la validité de la position désirée pour le coup. On retourne un message d'erreur approprié pour
        chacune des trois situations suivantes :

        1) Le coup tenté ne représente pas une position valide de la planche de jeu.

        2) Une pièce se trouve déjà à la position souhaitée.

        3) Le coup ne fait pas partie de la liste des coups valides.

        ATTENTION: Utilisez les méthodes et attributs de self.planche ainsi que la liste self.coups_possibles pour
                   connaître les informations nécessaires.
        ATTENTION: Bien que cette méthode valide plusieurs choses, les méthodes programmées dans la planche vous
                   simplifieront la tâche!

        Args:
            position_coup: La position du coup à valider.

        Returns:
            Un couple où le premier élément représente la validité de la position (True ou False), et le
            deuxième élément est un éventuel message d'erreur.
        """

        validite_position = True
        message_erreur = ""

        if not self.planche.position_valide(position_coup):
            validite_position = False
            message_erreur = "Le coup tenté ne représente pas une position valide de la planche de jeu."

        elif position_coup in self.planche.cases:
            validite_position = False
            message_erreur = "Une pièce se trouve déjà à la position souhaitée."

        elif position_coup not in self.coups_possibles:
            validite_position = False
            message_erreur = "Le coup ne fait pas partie de la liste des coups valides"

        return validite_position, message_erreur


    def tour(self):
        """
        Cette méthode simule le tour d'un joueur, et doit effectuer les actions suivantes:
        - Demander la position du coup au joueur courant. Tant que la position n'est pas validée, on continue de
          demander. Si la position est invalide, on affiche le message d'erreur correspondant. Pour demander la
          position, faites appel à la fonction choisir_coup de l'attribut self.joueur_courant, à laquelle vous
          devez passer la liste de coups possibles. Pour valider le coup retourné, pensez à la méthode de validation
          de coup que vous avez déjà à implémenter.
        - Jouer le coup sur la planche de jeu, avec la bonne couleur.
        - Si le résultat du coup est "erreur", afficher un message d'erreur.

        ***Vous disposez d'une méthode pour demander le coup à l'usager dans cette classe et la classe planche
        possède à son tour une méthode pour jouer un coup, utilisez-les !***
        """
        position_demande = self.joueur_courant.choisir_coup(self.coups_possibles)
        if not self.valider_position_coup(position_demande)[0]:
            message_erreur = self.valider_position_coup(position_demande)
            print(message_erreur[1])
            self.tour()

        coup_jouer = self.planche.jouer_coup(position_demande, self.couleur_joueur_courant)

        if coup_jouer == "erreur":
            print("Le déplacement n'a pas été effectuer car il n'est pas valide.")

    def passer_tour(self):
        """
        Affiche un message indiquant que le joueur de la couleur courante ne peut jouer avec l'état actuel de la
        planche et qu'il doit donc passer son tour.
        """
        print("Le joueur de couleur {} n'a aucun coup disponible,"
              " il doit donc passer son tour.".format(self.couleur_joueur_courant))


    def partie_terminee(self):
        """
        Détermine si la partie est terminée, Une partie est terminée si toutes les cases de la planche sont remplies
        ou si deux tours consécutifs ont été passés (pensez à l'attribut self.deux_tours_passes).
        """

        partie_terminee = False

        if len(self.planche.cases) >= 64:
            partie_terminee = True

        if self.deux_tours_passes:
            partie_terminee = True

        return partie_terminee

    def determiner_gagnant(self):
        """
        Détermine le gagnant de la partie. Le gagnant est simplement la couleur pour laquelle il y a le plus de
        pions sur la planche de jeu.

        Affichez un message indiquant la couleur gagnante ainsi que le nombre de pièces de sa couleur ou encore
        un message annonçant un match nul, le cas échéant.
        """
        compteur_blanc = 0
        compteur_noir = 0
        for piece in self.planche.cases.values():
            if piece.est_noir():
                compteur_noir += 1
            elif piece.est_blanc:
                compteur_blanc += 1
        

        if compteur_noir < compteur_blanc :
            message_gagnant = "Le joueur blanc est le gagnant avec {} pièces".format(compteur_blanc)

        elif compteur_blanc < compteur_noir:
            message_gagnant = "Le joueur noir est le gagnant avec {} pièces".format(compteur_noir)

        else:
            message_gagnant = "Aucun gagnant, c'est une match nul"

        print(message_gagnant)

    def jouer(self):
        """
        Démarre une partie. Tant que la partie n'est pas terminée, on fait les choses suivantes :

        1) On affiche la planche de jeu ainsi qu'un message indiquant à quelle couleur c'est le tour de jouer.
           Pour afficher une planche, faites appel à print(self.planche)

        2) On détermine les coups possibles pour le joueur actuel. Pensez à utiliser une fonction que vous avez à
           implémenter pour Planche, et à entreposer les coups possibles dans un attribut approprié de la partie.

        3) Faire appel à tour() ou à passer_tour(), en fonction du nombre de coups disponibles pour le joueur actuel.
           Mettez aussi à jour les attributs self.tour_precedent_passe et self.deux_tours_passes.

        4) Effectuer le changement de joueur. Modifiez à la fois les attributs self.joueur_courant et
           self.couleur_joueur_courant.

        5) Lorsque la partie est terminée, afficher un message mentionnant le résultat de la partie. Vous avez une
           fonction à implémenter que vous pourriez tout simplement appeler.
        """

        while not self.partie_terminee():
            print(self.planche)
            print("Joueur de couleur {}, c'est ton tour à jouer".format(self.couleur_joueur_courant))
            self.coups_possibles = self.planche.lister_coups_possibles_de_couleur(self.couleur_joueur_courant)

            if len(self.coups_possibles) > 0:
                self.tour()
                self.tour_precedent_passe = False

            elif len(self.coups_possibles) == 0:
                self.passer_tour()

                if self.tour_precedent_passe:
                    self.deux_tours_passes = True

                elif not self.tour_precedent_passe:
                    self.tour_precedent_passe = True

            if self.joueur_courant == self.joueur_noir:
                self.joueur_courant = self.joueur_blanc
                self.couleur_joueur_courant = "blanc"

            elif self.joueur_courant == self.joueur_blanc:
                self.joueur_courant = self.joueur_noir
                self.couleur_joueur_courant = "noir"

        # Print la planche final et annonce le gagnant
        print(self.planche)
        self.determiner_gagnant()

    def sauvegarder(self, nom_fichier):
        """
        Sauvegarde une partie dans un fichier. Le fichier condiendra:
        - Une ligne indiquant la couleur du joueur courant.
        - Une ligne contenant True ou False, si le tour précédent a été passé.
        - Une ligne contenant True ou False, si les deux derniers tours ont été passés.
        - Une ligne contenant le type du joueur blanc.
        - Une ligne contenant le type du joueur noir.
        - Le reste des lignes correspondant à la planche. Voir la méthode convertir_en_chaine de la planche
         pour le format.

        ATTENTION : L'ORDRE DES PARAMÈTRES SAUVEGARDÉS EST OBLIGATOIRE À RESPECTER.
                    Des tests automatiques seront roulés lors de la correction et ils prennent pour acquis que le
                    format plus haut est respecté. Vous perdrez des points si vous dérogez du format.

        Args:
            nom_fichier: Le nom du fichier où sauvegarder, un string.
        """
        partie_sauvegarde = open(nom_fichier, 'w')

        partie_sauvegarde.write(self.couleur_joueur_courant + "\n")
        partie_sauvegarde.write(str(self.tour_precedent_passe) + "\n")
        partie_sauvegarde.write(str(self.deux_tours_passes) + "\n")
        partie_sauvegarde.write(self.joueur_blanc.obtenir_type_joueur() + "\n")
        partie_sauvegarde.write(self.joueur_noir.obtenir_type_joueur() + "\n")
        partie_sauvegarde.write(self.planche.convertir_en_chaine())

        partie_sauvegarde.close()


    def charger(self, nom_fichier):
        """
        Charge une partie dans à partir d'un fichier. Le fichier a le même format que la méthode de sauvegarde.

        Args:
            nom_fichier: Le nom du fichier à charger, un string.
        """
        partie_charge = open(nom_fichier, 'r')

        self.couleur_joueur_courant = partie_charge.readline().strip("\n")
        self.tour_precedent_passe = eval(partie_charge.readline())
        self.deux_tours_passes = eval(partie_charge.readline())
        self.joueur_blanc = self.creer_joueur(partie_charge.readline().strip("\n"), "blanc")
        self.joueur_noir = self.creer_joueur(partie_charge.readline().strip("\n"), "noir")

        if self.couleur_joueur_courant == "blanc":
            self.joueur_courant = self.joueur_blanc

        elif self.couleur_joueur_courant == "noir":
            self.joueur_courant = self.joueur_noir

        char_planche = ""
        char_ajouter = partie_charge.readline()
        while char_ajouter != "":
            char_planche = char_planche + char_ajouter
            char_ajouter = partie_charge.readline()

        self.planche.charger_dune_chaine(char_planche)
        partie_charge.close()
Esempio n. 7
0
class Partie:
    def __init__(self, nom_fichier=None):
        """
        Méthode d'initialisation d'une partie. On initialise 4 membres:
        - planche: contient la planche de la partie, celui-ci contenant le dictionnaire de pièces.
        - couleur_joueur_courant: le joueur à qui c'est le tour de jouer.
        - tour_precedent_passe: un booléen représentant si le joueur précédent a passé son tour parce qu'il
           n'avait aucun coup disponible.
        - deux_tours_passes: un booléen représentant si deux tours ont été passés de suite, auquel cas la partie
           devra se terminer.
        - coups_possibles : une liste de tous les coups possibles en fonction de l'état actuel de la planche,
           initialement vide.

        On initialise ensuite les joueurs selon la paramètre nom_fichier. Si l'utilisateur a précisé un nom_fichier,
        on fait appel à la méthode self.charger() pour charger la partie à partir d'un fichier. Sinon, on fait appel
        à self.initialiser_joueurs(), qui va demander à l'utilisateur quels sont les types de joueurs qu'il désire.
        """
        self.planche = Planche()

        self.couleur_joueur_courant = "noir"

        self.tour_precedent_passe = False

        self.deux_tours_passes = False

        self.coups_possibles = []

        if nom_fichier is not None:
            self.charger(nom_fichier)
        else:
            self.initialiser_joueurs()

    def initialiser_joueurs(self):
        """
        On initialise ici trois attributs : joueur_noir, joueur_noir et joueur_courant (initialisé à joueur_noir).

        Pour créer les objets joueur, faites appel à demander_type_joueur()
        """
        self.joueur_noir = self.demander_type_joueur("noir")

        self.joueur_blanc = self.demander_type_joueur("blanc")

        self.joueur_courant = self.joueur_noir

    def demander_type_joueur(self, couleur):
        """
        Demande à l'usager quel type de joueur ('Humain' ou 'Ordinateur') il désire pour le joueur de la couleur.

        Tant que l'entrée n'est pas valide, on continue de demander à l'utilisateur.

        Faites appel à self.creer_joueur() pour créer le joueur lorsque vous aurez le type.

        :param couleur: La couleur pour laquelle on veut le type de joueur.
        :return: Un objet Joueur, de type JoueurHumain si l'usager a entré 'Humain', JoueurOrdinateur s'il a entré
        'Ordinateur'.
        """

        return self.creer_joueur("Humain", couleur)

    def creer_joueur(self, type, couleur):
        """
        Crée l'objet Joueur approprié, selon le type passé en paramètre.

        Pour créer les objets, vous n'avez qu'à faire appel à leurs constructeurs, c'est-à-dire à
        JoueurHumain(couleur), par exemple.

        :param type: le type de joueur, "Ordinateur" ou "Humain"
        :param couleur: la couleur du pion joué par le jouer, "blanc" ou "noir"
        :return: Un objet JoueurHumain si le type est "Humain", JoueurOrdinateur sinon
        """
        if type == 'Ordinateur':
            return JoueurOrdinateur(couleur)
        else:
            return JoueurHumain(couleur)

    def valider_position_coup(self, position_coup):
        """
        Vérifie la validité de la position désirée pour le coup. On retourne un message d'erreur approprié pour
        chacune des trois situations suivantes :

        1) Le coup tenté ne représente pas une position valide de la planche de jeu.

        2) Une pièce se trouve déjà à la position souhaitée.

        3) Le coup ne fait pas partie de la liste des coups valides.

        ATTENTION: Utilisez les méthodes et attributs de self.planche ainsi que la liste self.coups_possibles pour
                   connaître les informations nécessaires.
        ATTENTION: Bien que cette méthode valide plusieurs choses, les méthodes programmées dans la planche vous
                   simplifieront la tâche!

        :param position_coup: La position du coup à valider.
        :return: Un couple où le premier élément représente la validité de la position (True ou False), et le
                 deuxième élément est un éventuel message d'erreur.
        """
        if not self.planche.position_valide(position_coup):
            message = (
                "Position coup invalide: La position entrée est à l'extérieur de la planche de jeu."
            )
            return False, message

        if position_coup in self.planche.cases.keys():
            return False, "Position coup invalide: une pièce se trouve déjà à cette positon."

        if position_coup not in self.coups_possibles:
            message = "Position coup invalide: cette pièce ne peut pas faire de prise."
            return False, message

        return True, None

    def tour(self, position_coup):
        """
        Cette méthode simule le tour d'un joueur, et doit effectuer les actions suivantes:
        - Demander la position du coup au joueur courant. Tant que la position n'est pas validée, on continue de
          demander. Si la position est invalide, on affiche le message d'erreur correspondant. Pour demander la
          position, faites appel à la fonction choisir_coup de l'attribut self.joueur_courant, à laquelle vous
          devez passer la liste de coups possibles. Pour valider le coup retourné, pensez à la méthode de validation
          de coup que vous avez déjà à implémenter.
        - Jouer le coup sur la planche de jeu, avec la bonne couleur.
        - Si le résultat du coup est "erreur", afficher un message d'erreur.

        ***Vous disposez d'une méthode pour demander le coup à l'usager dans cette classe et la classe planche
        possède à son tour une méthode pour jouer un coup, utilisez-les !***
        """

        self.coups_possibles = self.planche.lister_coups_possibles_de_couleur(
            self.joueur_courant.couleur)
        position_valide, message = self.valider_position_coup(position_coup)

        if not position_valide:

            return False, message
        else:
            self.planche.jouer_coup(position_coup, self.couleur_joueur_courant)
            return True, ''

    def passer_tour(self):
        """
        Affiche un message indiquant que le joueur de la couleur courante ne peut jouer avec l'état actuel de la
        planche et qu'il doit donc passer son tour.
        """
        print("Aucun coup ne peut être joué pour le joueur " +
              self.joueur_courant.couleur + ". On passe le tour.")

    def partie_terminee(self):
        """
        Détermine si la partie est terminée, Une partie est terminée si toutes les cases de la planche sont remplies
        ou si deux tours consécutifs ont été passés (pensez à l'attribut self.deux_tours_passes).
        """
        return len(self.planche.cases.keys()
                   ) == self.planche.nb_cases**2 or self.deux_tours_passes

    def determiner_gagnant(self):
        """
        Détermine le gagnant de la partie. Le gagnant est simplement la couleur pour laquelle il y a le plus de
        pions sur la planche de jeu.

        Affichez un message indiquant la couleur gagnante ainsi que le nombre de pièces de sa couleur ou encore
        un message annonçant un match nul, le cas échéant.
        """
        assert self.partie_terminee(
        ), "obtenir_gagnant(): La partie n'est pas encore terminée !"

        n_blancs, n_noirs = 0, 0
        for _, p in self.planche.cases.items():
            if p.est_blanc():
                n_blancs += 1
            else:
                n_noirs += 1

        # les message box vont afficher les detail de la partie terminee
        if n_blancs == n_noirs:
            messagebox.showinfo("Partie Terminé!!", "Match nul!")

        elif n_blancs > n_noirs:
            messagebox.showinfo(
                "Partie Terminé!!",
                "Le gagnant est le joueur blanc avec {} pièces !".format(
                    n_blancs))

        else:
            messagebox.showinfo(
                "Partie Terminé!!",
                "Le gagnant est le joueur noir avec {} pièces !".format(
                    n_noirs))

    def jouer(self, coup):
        """
        Démarre une partie. Tant que la partie n'est pas terminée, on fait les choses suivantes :

        1) On affiche la planche de jeu ainsi qu'un message indiquant à quelle couleur c'est le tour de jouer.
           Pour afficher une planche, faites appel à print(self.planche)

        2) On détermine les coups possibles pour le joueur actuel. Pensez à utiliser une fonction que vous avez à
           implémenter pour Planche, et à entreposer les coups possibles dans un attribut approprié de la partie.

        3) Faire appel à tour() ou à passer_tour(), en fonction du nombre de coups disponibles pour le joueur actuel.
           Mettez aussi à jour les attributs self.tour_precedent_passe et self.deux_tours_passes.

        4) Effectuer le changement de joueur. Modifiez à la fois les attributs self.joueur_courant et
           self.couleur_joueur_courant.

        5) Lorsque la partie est terminée, afficher un message mentionnant le résultat de la partie. Vous avez une
        fonction à implémenter que vous pourriez tout simplement appeler.
        """
        coup_valide = False
        message = ''
        if not self.partie_terminee():

            self.coups_possibles = self.planche.lister_coups_possibles_de_couleur(
                self.joueur_courant.couleur)
            # determine si joueur courant peut jouer
            if len(self.coups_possibles) > 0:
                self.tour_precedent_passe = False
                coup_valide, message = self.tour(coup)

            else:
                if self.tour_precedent_passe:
                    self.deux_tours_passes = True
                self.passer_tour()
                self.tour_precedent_passe = True

            if coup_valide and self.joueur_courant.couleur == "blanc":
                self.joueur_courant = self.joueur_noir
                self.couleur_joueur_courant = "noir"
            elif coup_valide:
                self.joueur_courant = self.joueur_blanc
                self.couleur_joueur_courant = "blanc"
        else:
            message = self.determiner_gagnant()
        return message

    def sauvegarder(self, nom_fichier):
        """
        Sauvegarde une partie dans un fichier. Le fichier contiendra:
        - Une ligne indiquant la couleur du joueur courant.
        - Une ligne contenant True ou False, si le tour précédent a été passé.
        - Une ligne contenant True ou False, si les deux derniers tours ont été passés.
        - Une ligne contenant le type du joueur blanc.
        - Une ligne contenant le type du joueur noir.
        - Le reste des lignes correspondant à la planche. Voir la méthode convertir_en_chaine de la planche
         pour le format.

        ATTENTION : L'ORDRE DES PARAMÈTRES SAUVEGARDÉS EST OBLIGATOIRE À RESPECTER.
                    Des tests automatiques seront roulés lors de la correction et ils prennent pour acquis que le
                    format plus haut est respecté. Vous perdrez des points si vous dérogez du format.

        :param nom_fichier: Le nom du fichier où sauvegarder.
        :type nom_fichier: string.
        """
        with open(nom_fichier, "w") as f:
            f.write("{}\n".format(self.joueur_courant.couleur))
            f.write("{}\n".format(self.tour_precedent_passe))
            f.write("{}\n".format(self.deux_tours_passes))
            f.write("{}\n".format(self.joueur_blanc.obtenir_type_joueur()))
            f.write("{}\n".format(self.joueur_noir.obtenir_type_joueur()))
            f.writelines(self.planche.convertir_en_chaine())

    def charger(self, nom_fichier):
        """
        Charge une partie dans à partir d'un fichier. Le fichier a le même format que la méthode de sauvegarde.

        :param nom_fichier: Le nom du fichier à charger.
        :type nom_fichier: string.
        """
        with open(nom_fichier) as f:
            self.couleur_joueur_courant = f.readline().rstrip("\n")
            self.tour_precedent_passe = True if f.readline().rstrip(
                "\n") == "True" else False
            self.deux_tours_passes = True if f.readline().rstrip(
                "\n") == "True" else False
            self.joueur_blanc = self.creer_joueur(f.readline().rstrip("\n"),
                                                  "blanc")
            self.joueur_noir = self.creer_joueur(f.readline().rstrip("\n"),
                                                 "noir")
            self.joueur_courant = self.joueur_blanc if self.couleur_joueur_courant == "blanc" else self.joueur_noir

            self.planche.charger_dune_chaine(f.read())
Esempio n. 8
0
class Partie:
    def __init__(self):
        self.planche = Planche()

        self.couleur_joueur_courant = "noir"

        self.tour_precedent_passe = False

        self.deux_tours_passes = False

        self.coups_possibles = []

        self.initialiser_joueurs()

    def initialiser_joueurs(self):
        self.joueur_noir = self.creer_joueur('noir')
        self.joueur_blanc = self.creer_joueur('blanc')
        self.joueur_courant = self.joueur_noir

    def creer_joueur(self, couleur):
        if couleur.lower() == "blanc":
            return JoueurHumain("blanc")
        else:
            return JoueurHumain("noir")

    def obtenir_couleur_joueur_adverse(self):
        if self.couleur_joueur_courant == "noir":
            return "blanc"
        return "noir"

    def valider_position_coup(self, position_coup):
        # On lance une exception pour tout type de situation qui empêche un joueur
        # de jouer un coup.
        valide = True
        erreur = ""

        if not self.planche.position_valide(position_coup):
            erreur = "Position coup invalide: la position entrée est à l'extérieur de la planche de jeu.\n"
            raise ErreurExceptionCoup(erreur)
        elif self.planche.get_piece(position_coup) is not None:
            erreur = "Position coup invalide: une pièce se trouve déjà à cette position.\n"
            raise ErreurExceptionCoup(erreur)
        elif position_coup not in self.coups_possibles:
            erreur = "Position coup invalide: cette pièce ne peut pas faire de prise.\n"
            raise ErreurExceptionCoup(erreur)
        return valide, erreur

    def tour(self, position):
        # On joue le tour présent en vérifiant s'il termine la partie.
        # Sinon, on valide le coup et on procède au changement de couleur si tout est dans l'ordre.
        # On vérifie finalement si un coup peut être joué dans le tour suivant.
        self.coups_possibles = self.planche.lister_coups_possibles_de_couleur(self.couleur_joueur_courant)

        if not self.valider_position_coup(position)[0]:
            return
        self.planche.jouer_coup(position, self.couleur_joueur_courant)
        if self.partie_terminee():
            return

        self.changer_couleur()
        self.verifier_prochain_tour()

    def verifier_prochain_tour(self):
        # On vérifie si un coup peut être joué dans ce tour, si oui on retourne,
        # sinon on passe le tour.
        self.coups_possibles = self.planche.lister_coups_possibles_de_couleur(self.couleur_joueur_courant)

        if len(self.coups_possibles) == 0:
            self.passer_tour()
            return
        else:
            self.tour_precedent_passe = False

    def passer_tour(self):
        # On passe le tour et on met l'attribut de vérification du tour_precedent à vrai.
        # L'exception est lancée et affiche l'erreur au joueur avec une description.
        self.tour_precedent_passe = True
        self.changer_couleur()
        self.coups_possibles = self.planche.lister_coups_possibles_de_couleur(self.couleur_joueur_courant)

        if len(self.coups_possibles) == 0:
            self.deux_tours_passes = True
            return
        joueur_adverse = self.obtenir_couleur_joueur_adverse()
        raise ErreurExceptionCoup("Le joueur " + joueur_adverse + " ne peut pas jouer avec l'état actuel de la planche,"
                                                           " il doit donc passer son tour.\n")

    def changer_couleur(self):
        if self.joueur_courant.couleur == "noir":
            self.joueur_courant = self.joueur_blanc
            self.couleur_joueur_courant = "blanc"
        else:
            self.joueur_courant = self.joueur_noir
            self.couleur_joueur_courant = "noir"

    def partie_terminee(self):
        # S'il y a 64 pièces sur la planche ou que deux tours sont passés, la partie est terminée.
        if len(self.planche.cases.keys()) > 63 or self.deux_tours_passes is True:
            return True
        return False

    def determiner_gagnant(self):
        # Maintenant que la partie est terminée, on compte les pièces sur la planche pour déclarer le résultat.
        noir = 0
        blanc = 0
        deux_tours = ""

        if self.deux_tours_passes:
            deux_tours = "Deux tours passés, fin de partie.\n"

        for coords in self.planche.cases:
            if self.planche.cases[coords].couleur == "noir":
                noir += 1
            else:
                blanc += 1

        if noir > blanc:
            return(deux_tours + "Le gagnant est le joueur noir avec " + str(noir) + " pièces.")
        elif noir < blanc:
            return(deux_tours + "Le gagnant est le joueur blanc avec " + str(blanc) + " pièces.")
        else:
            return(deux_tours + "Match nul.")
Esempio n. 9
0
class Partie:
    def __init__(self, nom_fichier = None):
        """
        Méthode d'initialisation d'une partie. On initialise 4 membres:
        - planche: contient la planche de la partie, celui-ci contenant le dictionnaire de pièces.
        - couleur_joueur_courant: le joueur à qui c'est le tour de jouer.
        - tour_precedent_passe: un booléen représentant si le joueur précédent a passé son tour parce qu'il
           n'avait aucun coup disponible.
        - deux_tours_passes: un booléen représentant si deux tours ont été passés de suite, auquel cas la partie
           devra se terminer.
        - coups_possibles : une liste de tous les coups possibles en fonction de l'état actuel de la planche,
           initialement vide.

        On initialise ensuite les joueurs selon la paramètre nom_fichier. Si l'utilisateur a précisé un nom_fichier,
        on fait appel à la méthode self.charger() pour charger la partie à partir d'un fichier. Sinon, on fait appel
        à self.initialiser_joueurs(), qui va demander à l'utilisateur quels sont les types de joueurs qu'il désire.
        """

        # La planche possede des None aux emplacementss vide (non prévu dans l'énnoncé) pour plus de facilité dans son parcours
        self.planche = Planche()    

        # Le joueur noir commence
        self.couleur_joueur_courant = "noir"

        self.tour_precedent_passe = False

        self.deux_tours_passes = False

        self.coups_possibles = []
  
        self.couleur_joueur_courant = "noir"

        if nom_fichier is not None:
            self.charger(nom_fichier)
        else:
            self.initialiser_joueurs()

    def initialiser_joueurs(self):
        """
        On initialise ici trois attributs : joueur_noir, joueur_blanc et joueur_courant (initialisé à joueur_noir).

        Pour créer les objets joueur, faites appel à demander_type_joueur()
        """
        self.joueur_blanc = self.demander_type_joueur("blanc")
        self.joueur_noir = self.demander_type_joueur("noir")
        self.joueur_courant = self.joueur_noir

    def demander_type_joueur(self, couleur):
        """
        Demande à l'usager quel type de joueur ('Humain' ou 'Ordinateur') il désire pour le joueur de la couleur.

        Tant que l'entrée n'est pas valide, on continue de demander à l'utilisateur.

        Faites appel à self.creer_joueur() pour créer le joueur lorsque vous aurez le type.

        Args:
            couleur: La couleur pour laquelle on veut le type de joueur.

        Returns:
            Un objet Joueur, de type JoueurHumain si l'usager a entré 'Humain', JoueurOrdinateur s'il a entré
            'Ordinateur'.
        """
        
        reponse = input("Quel type de joueur sera " + couleur + " ?")
        while reponse not in ['Humain', 'Ordinateur']:
            print("Vous devez repondre Ordinateur ou Humain !!")
            reponse = input("Quel type de joueur sera " + couleur + " ?")
        
        return self.creer_joueur(reponse, couleur)

    def creer_joueur(self, type, couleur):
        """
        Crée l'objet Joueur approprié, selon le type passé en paramètre.

        Pour créer les objets, vous n'avez qu'à faire appel à leurs constructeurs, c'est-à-dire à
        JoueurHumain(couleur), par exemple.

        Args:
            type: le type de joueur, "Ordinateur" ou "Humain"
            couleur: la couleur du pion joué par le jouer, "blanc" ou "noir"

        Returns:
            Un objet JoueurHumain si le type est "Humain", JoueurOrdinateur sinon
        """
        
        if type == "Ordinateur":
            return JoueurOrdinateur(couleur)
        else:
            return JoueurHumain(couleur)


    def valider_position_coup(self, position_coup):
        """
        Vérifie la validité de la position désirée pour le coup. On retourne un message d'erreur approprié pour
        chacune des trois situations suivantes :

        1) Le coup tenté ne représente pas une position valide de la planche de jeu.

        2) Une pièce se trouve déjà à la position souhaitée.

        3) Le coup ne fait pas partie de la liste des coups valides.

        ATTENTION: Utilisez les méthodes et attributs de self.planche ainsi que la liste self.coups_possibles pour
                   connaître les informations nécessaires.
        ATTENTION: Bien que cette méthode valide plusieurs choses, les méthodes programmées dans la planche vous
                   simplifieront la tâche!

        Args:
            position_coup: La position du coup à valider.

        Returns:
            Un couple où le premier élément représente la validité de la position (True ou False), et le
            deuxième élément est un éventuel message d'erreur.
        """
        
        coup_valide = False
        message_erreur = ""
        # 1) Le coup tenté représente une position valide de la planche de jeu.
        if self.planche.position_valide(position_coup):
            # 2) Aucune pièce se trouve déjà à la position souhaitée.
            if self.planche.cases[(position_coup)] is None:
                # 3) Le coup fait partie de la liste des coups valides.
                if position_coup in self.coups_possibles:
                    coup_valide = True
                else:
                    message_erreur = "Le coup ne fait pas partie de la liste des coups valides \n"
            else:
                message_erreur = "Une piece se trouve deja a cette position \n"
        else:
            message_erreur = "La position n est pas sur la planche de jeu \n"

        return (coup_valide, message_erreur)

    def tour(self):
        """
        Cette méthode simule le tour d'un joueur, et doit effectuer les actions suivantes:
        - Demander la position du coup au joueur courant. Tant que la position n'est pas validée, on continue de
          demander. Si la position est invalide, on affiche le message d'erreur correspondant.
           Pour demander la
          position, faites appel à la fonction choisir_coup de l'attribut self.joueur_courant, à laquelle vous
          devez passer la liste de coups possibles. Pour valider le coup retourné, pensez à la méthode de validation
          de coup que vous avez déjà à implémenter.
        - Jouer le coup sur la planche de jeu, avec la bonne couleur.
        - Si le résultat du coup est "erreur", afficher un message d'erreur.

        ***Vous disposez d'une méthode pour demander le coup à l'usager dans cette classe et la classe planche
        possède à son tour une méthode pour jouer un coup, utilisez-les !***
        """
        if self.joueur_courant.obtenir_type_joueur() == "Ordinateur":
            coup_ordinateur = self.joueur_courant.choisir_coup(self.planche.lister_coups_possibles_de_couleur(self.couleur_joueur_courant))
            self.planche.jouer_coup(coup_ordinateur, self.couleur_joueur_courant)

        if self.joueur_courant.obtenir_type_joueur() == "Humain":

            # L utilisateur choisit un coup qui fonctionne
            position_choisie = self.joueur_courant.choisir_coup(self.planche.lister_coups_possibles_de_couleur(self.joueur_courant.couleur))

            # Tant que la position choisie n est pas correct on lui redemande
            while not self.valider_position_coup(position_choisie)[0]:
                print(self.valider_position_coup(position_choisie)[1])
                position_choisie = self.joueur_courant.choisir_coup(self.planche.lister_coups_possibles_de_couleur(self.joueur_courant.couleur))
            # On joue le coup choisi
            print (self.planche.jouer_coup(position_choisie, self.joueur_courant.couleur))

    def passer_tour(self):
        """
        Affiche un message indiquant que le joueur de la couleur courante ne peut jouer avec l'état actuel de la
        planche et qu'il doit donc passer son tour.
        """


        print("Le joueur {} ne peut pas jouer et passe son tour".format(self.couleur_joueur_courant))
        self.changerTour()


    def partie_terminee(self):
        """
        Détermine si la partie est terminée, Une partie est terminée si toutes les cases de la planche sont remplies
        ou si deux tours consécutifs ont été passés (pensez à l'attribut self.deux_tours_passes).
        """

        # Si deux tours sont passés de suite la partie est terminee
        if self.deux_tours_passes:
            self.determiner_gagnant()
            return True
        
        # Si il reste aucune case vide la partie est terminee
        is_partie_terminee = True
        for case in self.planche.cases.values():
            if case is None:
                is_partie_terminee = False

        # partie terminee on indique le gagnant
        if is_partie_terminee:
            self.determiner_gagnant()
            return True
        return False
        

    def determiner_gagnant(self):
        """
        Détermine le gagnant de la partie. Le gagnant est simplement la couleur pour laquelle il y a le plus de
        pions sur la planche de jeu.

        Affichez un message indiquant la couleur gagnante ainsi que le nombre de pièces de sa couleur ou encore
        un message annonçant un match nul, le cas échéant.
        """
        nombre_de_noir = 0
        nombre_de_blanc = 0

        for case in self.planche.cases.values():
            if type(case) is Piece:
                if case.couleur == "noir":
                    nombre_de_noir += 1
                else:
                    nombre_de_blanc += 1