126 lines
3 KiB
Python
126 lines
3 KiB
Python
|
#!/usr/bin/env python
|
||
|
|
||
|
"""Jeu de Hanoï pour implémenter des piles"""
|
||
|
|
||
|
from typing import Optional
|
||
|
|
||
|
|
||
|
def main() -> None:
|
||
|
p1 = Pile()
|
||
|
p2 = Pile()
|
||
|
p3 = Pile()
|
||
|
|
||
|
p2 = ajout_tous_disques(p2)
|
||
|
|
||
|
while not partie_finie(p1, p2, p3):
|
||
|
affiche_etat_piles(p1, p2, p3)
|
||
|
faire_coup(p1, p2, p3)
|
||
|
|
||
|
print("Bravo, vous avez terminé")
|
||
|
|
||
|
|
||
|
class Pile:
|
||
|
"""Une pile composée de maillons"""
|
||
|
|
||
|
def __init__(self) -> None:
|
||
|
self.val: Optional[int] = None
|
||
|
self.suivant: Optional[Pile] = None
|
||
|
|
||
|
def est_vide(self) -> bool:
|
||
|
"""Vérifie si la pile est vide"""
|
||
|
|
||
|
return self.suivant is None
|
||
|
|
||
|
def empile(self, nombre: int):
|
||
|
"""Empile nombre sur la pile"""
|
||
|
|
||
|
maillon = Pile()
|
||
|
maillon.val = nombre
|
||
|
maillon.suivant = self
|
||
|
return maillon
|
||
|
|
||
|
def depile(self):
|
||
|
"""Dépile la pile"""
|
||
|
|
||
|
return self.suivant
|
||
|
|
||
|
def valeur_top(self) -> Optional[int]:
|
||
|
"""Retourne la valeur en haut de la pile sans dépiler"""
|
||
|
|
||
|
if self.est_vide():
|
||
|
return None
|
||
|
return self.val
|
||
|
|
||
|
|
||
|
def ajout_tous_disques(pile: Pile) -> Pile:
|
||
|
"""Ajoute tous les disques sur p"""
|
||
|
|
||
|
nombre_disques = int(input("Combien de disques ? "))
|
||
|
while nombre_disques >= 1:
|
||
|
pile = pile.empile(nombre_disques)
|
||
|
nombre_disques -= 1
|
||
|
return pile
|
||
|
|
||
|
|
||
|
def partie_finie(p1: Pile, p2: Pile, p3: Pile) -> bool:
|
||
|
"""Détermine si la partie est finie"""
|
||
|
|
||
|
return p2.est_vide() and (p1.est_vide() or p3.est_vide())
|
||
|
|
||
|
|
||
|
def affiche_etat_piles(p1: Pile, p2: Pile, p3: Pile) -> None:
|
||
|
"""Afficher l'état des trois piles"""
|
||
|
|
||
|
print("Pile 1 :")
|
||
|
affiche_etat(p1)
|
||
|
print("Pile 2 :")
|
||
|
affiche_etat(p2)
|
||
|
print("Pile 3 :")
|
||
|
affiche_etat(p3)
|
||
|
|
||
|
|
||
|
def affiche_etat(pile: Pile) -> None:
|
||
|
"""Affiche l'état d'une pile"""
|
||
|
|
||
|
if pile.est_vide():
|
||
|
print("La pile est vide")
|
||
|
else:
|
||
|
diam = pile.valeur_top()
|
||
|
print(f"Le disque en haut de la pile est de diamètre {diam}")
|
||
|
|
||
|
|
||
|
def faire_coup(p1: Pile, p2: Pile, p3: Pile) -> None:
|
||
|
"""Demande à l'utilisateur de jouer"""
|
||
|
|
||
|
num_pile = int(input("Où voulez-vous prendre le disque ? "))
|
||
|
pile_a_depiler = selection_pile(p1, p2, p3, num_pile)
|
||
|
|
||
|
if pile_a_depiler.est_vide():
|
||
|
print("Impossible, cette pile est vide")
|
||
|
return
|
||
|
diam = pile_a_depiler.valeur_top()
|
||
|
print(f"Vous avez sélectionné le disque de diamètre {diam}")
|
||
|
|
||
|
num_pile = int(input("Où voulez-vous poser le disque ? "))
|
||
|
pile_ou_empiler = selection_pile(p1, p2, p3, num_pile)
|
||
|
|
||
|
if not pile_ou_empiler.est_vide() and diam > pile_ou_empiler.valeur_top():
|
||
|
print("Coup non autorisé")
|
||
|
else:
|
||
|
pile_a_depiler = pile_a_depiler.depile()
|
||
|
pile_ou_empiler = pile_ou_empiler.empile(diam)
|
||
|
|
||
|
|
||
|
def selection_pile(p1: Pile, p2: Pile, p3: Pile, num_pile: int) -> Pile:
|
||
|
"""Retourne la pile correspondant à num_pile"""
|
||
|
|
||
|
if num_pile == 1:
|
||
|
return p1
|
||
|
if num_pile == 2:
|
||
|
return p2
|
||
|
return p3
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
main()
|