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
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()
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.")
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())
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