diff --git a/minimax.py b/minimax.py index 510ded9..b879aea 100644 --- a/minimax.py +++ b/minimax.py @@ -13,12 +13,15 @@ class Morpion(): - Le joueur B se nomme `O`. - Le plateau à une taille `3x3`. """ + self.erreur = False if len(joueurA) != 1 or len(joueurB) != 1: # Gestion erreur nom des joueurs print("Nom des joueurs invalide.") + self.erreur = True return self.plateau: list = self._definitionPlateau(taille[0], taille[1]) if len(self.plateau) == 0: # Gestion erreur du plateau print("Taille du plateau invalide.") + self.erreur = True return self.nbCasesGagnantes = self._recuperationNbCasesGagnantes() # définit combien de cases les joueurs doivent aligner pour gagner self.joueurA = joueurA # définit le joueur A @@ -164,10 +167,10 @@ class Morpion(): """Renvoie les coordonnées d'une case.""" return ((numero - 1) // len(self.plateau[0]), (numero - 1) % len(self.plateau[0])) - def _placementPiece(self, joueur: str, n: int) -> None: + def _placementPiece(self, valeur, n: int) -> None: # valeur est une Union de str et int car il peut être ammené à être modifié avec Minimax """Place la pièce d'un joueur dans le plateau.""" x, y = self._coordonneesCaseDepuisNumero(n) - self.plateau[x][y] = joueur + self.plateau[x][y] = valeur def _demandeCase(self, joueur) -> int: """Demande au joueur sur quelle case il veut poser sa pièce.""" @@ -231,24 +234,65 @@ class Morpion(): class Minimax(Morpion): """Définition de l'algorithme Minimax.""" - def __init__(self, joueurA: str = 'X', joueurB: str = 'O', taille: tuple = (3, 3)) -> None: + def __init__(self, humain: str = 'X', ordinateur: str = 'O', taille: tuple = (3, 3)) -> None: """ Initalise la classe Minimax héritant du Morpion. - Taille par défaut : `3x3`. - Joueur A est l'humain. - Joueur B est l'ordinateur. """ - super().__init__(joueurA, joueurB, taille = taille) + super().__init__(humain, ordinateur, taille = taille) + if self.erreur: # en cas d'erreur dans la classe parent + return + self.humain = self.joueurA + self.robot = self.joueurB def _demandeCaseB(self) -> int: """Utilise l'algorithme `Minimax` pour jouer le coup du joueur B.""" - return self.minimax() + return self.minimax(self.robot)[1] - def minimax(self) -> list: - """ - Fonction Minimax qui décide quel case est la plus intéressante. - """ - return super()._demandeCaseB() + def _terminerOuEgaliter(self) -> bool: + """Retourne vrai si il y a un gagnant ou si le plateau est plein.""" + return not len(self.gagnant) == 0 or self._egalite() + + def _coupsPossibles(self) -> list: + coups = [] + for i in range(len(self.plateau)): + for j in range(len(self.plateau[i])): + if not self._caseOccupee(i, j): + coups.append(self.plateau[i][j]) + return coups + + def _ennemi(self, joueur) -> list: + if joueur == self.humain: + return self.robot + return self.humain + + def minimax(self, joueur: str, profondeur: int = 0) -> list: + """Fonction Minimax qui décide quel case est la plus intéressante.""" + # return super()._demandeCaseB() # On ne change rien au comportement du Morpion + if joueur == self.robot: + meilleursCas = -10 + else: + meilleursCas = 10 + if self._terminerOuEgaliter(): + if self.gagnant == self.humain : + return -10 + profondeur, None + elif self._egalite(): + return 0, None + elif self.gagnant == self.robot: + return 10 - profondeur, None + for numero in self._coupsPossibles(): + self._placementPiece(joueur, numero) + valeurEvaluation, _ = self.minimax(self._ennemi(joueur), profondeur + 1) + self._placementPiece(numero, numero) + if joueur == self.robot: + if valeurEvaluation > meilleursCas: + meilleursCas, meilleurNumero = valeurEvaluation, numero + else: + if valeurEvaluation < meilleursCas: + meilleursCas, meilleurNumero = valeurEvaluation, numero + return meilleursCas, meilleurNumero if __name__ == "__main__": # Si on lance directement le fichier et on s'en sert pas comme module """ @@ -286,5 +330,6 @@ if __name__ == "__main__": # Si on lance directement le fichier et on s'en sert else: Minimax(sys.argv[0], sys.argv[1], tuple([int(i) for i in sys.argv[2].split('x')])).jouer() # On spécifie les joueurs et la taille du tableau except Exception as e: - print(f"Un argument n'a pas été compris ({e})... Lancement du Morpion avec les paramètres par défaut.") + if not "list index out of range" in str(e): + print(f"Un argument n'a pas été compris ({e})... Lancement du Morpion avec les paramètres par défaut.") Minimax().jouer() # On lance la partie à l'instanciation du Morpion