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, 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())