Certains s'empilent, d'autres se défilent...
Des chapeaux et des bonhommes de neige¶
Cinq chapeaux empilés sont distribués, en commençant en haut et allant vers le bas, à cinq bons hommes de neige en commençant à gauche et finissant à droite. À la fin, chaque bonhomme de neige devrait recevoir un chapeau à sa taille.

Quelle pile de chapeaux correspond à quelle rangée de bonshommes de neige ?
Une pile de chapeaux¶
On représente un chapeau par un objet de type Chapeau qui possède un attribut taille qui représente sa taille : ainsi le plus petit chapeau a une taille de 1, et le plus grand chapeau a une taille de 5. On modélise une pile de chapeaux par un objet de type Pile.
Les interfaces des classes Chapeau et Pile sont les suivantes :
-
classe
ChapeauFonction Signature Description Chapeau(c)int -> ChapeauRenvoie un chapeau de taille cc.affiche()() -> NoneAffiche le chapeau c -
classe
PileFonction Signature Description Pile()() -> PileCréer une pile vide p.est_vide()() -> BoolDétermine si la pile pest vide.p.empiler(c)Chapeau -> NoneDéposer le chapeau cau sommet de la pilepp.depiler()() -> ChapeauRenvoie le chapeau au sommet de la pile p,lorsque cela est possible. p.affiche()() -> NoneAffiche la pile psans la modifier.
Exécuter le bloc ci-dessous pour charger les classes Chapeau et Pile.
#--- HDR ---#bksl-nlclass Chapeau:bksl-nl def py-undpy-undinitpy-undpy-und(self, t):bksl-nl self.taille = tbksl-nlbksl-nl def py-undpy-undreprpy-undpy-und(self):bksl-nl return f"Chap. {self.taille}"bksl-nlbksl-nl def affiche(self):bksl-nl print(self)bksl-nlbksl-nlclass Pile:bksl-nl def py-undpy-undinitpy-undpy-und(self, maxpy-undelt = float('inf')):bksl-nl self.contenu = []bksl-nl self.maxpy-undelt = maxpy-undeltbksl-nlbksl-nl def py-undpy-undreprpy-undpy-und(self):bksl-nl return "[" + ", ".join(b.py-undpy-undreprpy-undpy-und() for b in self.contenu) + "] (Sommet pile)" bksl-nlbksl-nl def affiche(self):bksl-nl print(self)bksl-nlbksl-nl def estpy-undvide(self):bksl-nl return self.contenu == []bksl-nlbksl-nl def estpy-undpleine(self):bksl-nl return self.maxpy-undelt == len(self.contenu)bksl-nlbksl-nl def empiler(self, c):bksl-nl # assert isinstance(c, Chapeau)bksl-nl if self.estpy-undpleine():bksl-nl raise IndexError("Capacité maximale de la pile atteinte")bksl-nl self.contenu.append(c)bksl-nlbksl-nl def depiler(self):bksl-nl if self.estpy-undvide():bksl-nl raise IndexError("Impossible de dépiler : la pile est vide.")bksl-nl return self.contenu.pop()bksl-nl#--- HDR ---#bksl-nl# Exécuter ce bloc AVANT de traiter les exercices.bksl-nl# Charge les classes Chapeau et Pile.bksl-nlbksl-nlc = Chapeau(1)bksl-nlp = Pile()bksl-nlp.empiler(c)bksl-nlp.empiler(Chapeau(2))bksl-nlp.affiche()bksl-nlprint(p.depiler())bksl-nlbksl-nl
Écrire le code python d'une fonction init_piles qui renvoie les 4 piles p1, p2, p3 et p4 représentant respectivement les piles de chapeaux 1, 2, 3, et 4.
def initpy-undpiles():bksl-nl p1 = Pile()bksl-nl # p1.empiler(...)bksl-nl # ...bksl-nl # À compléterbksl-nl return p1, p2, p3, p4bksl-nlbksl-nl
Une file de bonshommes de neige¶
On représente un bonhomme de neige par un objet de type Bonhomme muni d'un attribut taille qui représente sa taille : ainsi le plus petit bonhomme de neige a une taille de 1, et le plus grand bonhomme de neige a une taille de 5. Si b est un objet de type Bonhomme et c un objet de type Chapeau, alors b.content(c) renvoie True si et seulement si le chapeau c est celui du bonhomme b.
On modélise une file de bonshommes de neige par un objet de type File, qui contient les bonshommes de neige.
Les interfaces des classes Bonhomme et File sont les suivantes :
-
classe
BonhommeFonction Signature Description Bonhomme(b)int -> BonhommeRenvoie un bonhomme de taille bb.content(c)Chapeau -> BoolRenvoie Truesi le chapeaucconvient au bonhommebb.affiche()() -> NoneAffiche le bonhomme b -
classe
FileFonction Signature Description File()() -> FileCréer une file vide f.est_vide()() -> BoolDétermine si la file fest vide.f.enfiler(c)Bonhomme -> NoneDéposer le bonhomme bà la fin de la fileff.defiler()() -> BonhommeRenvoie le premier bonhomme de la file f,lorque cela est possible. f.affiche()() -> NoneAffiche la file fsans la modifier.
Exécuter le bloc ci-dessous pour charger les classes Bonhomme et File.
#--- HDR ---#bksl-nlclass Bonhomme:bksl-nl def py-undpy-undinitpy-undpy-und(self, t):bksl-nl self.taille = tbksl-nlbksl-nl def py-undpy-undreprpy-undpy-und(self):bksl-nl return f"Bonh. {self.taille}"bksl-nlbksl-nl def affiche(self):bksl-nl print(self)bksl-nlbksl-nl def content(self, c):bksl-nl return c.taille == self.taillebksl-nlbksl-nlclass File:bksl-nl def py-undpy-undinitpy-undpy-und(self, maxpy-undelt = float('inf')):bksl-nl self.contenu = []bksl-nl self.maxpy-undelt = maxpy-undeltbksl-nlbksl-nl def py-undpy-undreprpy-undpy-und(self):bksl-nl return "(Début file) [" + ", ".join(b.py-undpy-undreprpy-undpy-und() for b in self.contenu) + "]"bksl-nlbksl-nl def affiche(self):bksl-nl print(self)bksl-nlbksl-nl def estpy-undvide(self):bksl-nl return self.contenu == []bksl-nlbksl-nl def estpy-undpleine(self):bksl-nl return len(self.contenu) == self.maxpy-undelt bksl-nlbksl-nl def enfiler(self, b):bksl-nl # assert isinstance(b, Bonhomme)bksl-nl if self.estpy-undpleine():bksl-nl raise IndexError("Capacité maximale de la file atteinte")bksl-nl self.contenu.append(b)bksl-nlbksl-nl def defiler(self):bksl-nl if self.estpy-undvide():bksl-nl raise IndexError("Impossible de défiler : la file est vide.")bksl-nl return self.contenu.pop(0)bksl-nl#--- HDR ---#bksl-nl# Exécuter ce bloc AVANT de traiter les exercices.bksl-nl# Charge les classes Bonhomme et File.bksl-nlbksl-nlb = Bonhomme(1)bksl-nlf = File()bksl-nlf.enfiler(b)bksl-nlf.enfiler(Bonhomme(2))bksl-nlf.affiche()bksl-nlprint(f.defiler())bksl-nlbksl-nl
Écrire le code python d'une fonction init_files qui renvoie les 4 files f1, f2, f3 et f4 représentant respectivement les files de bonshommes de neige 1, 2, 3, et 4.
def initpy-undfiles():bksl-nl f1 = File()bksl-nl # f1.enfiler(...)bksl-nl # ...bksl-nl # À compléter.bksl-nl return f1, f2, f3, f4bksl-nlbksl-nl
Compatiblité entre pile de chapeaux et file de bonshommes¶
On dit qu'une pile de chapeaux est compatible avec une file de bonshommes de neige si et seulement si tous les bonhommes de neige sont content lorsqu'ils prennent le premier chapeau de la pile dans l'ordre imposé par la file.
On se propose de résoudre le problème de l'association d'une pile de chapeaux avec une file de bonshommes de neige. On souhaite écrire une fonction compatibles qui étant donné une pile de chapeaux p et une file de bonshommes de neige f, renvoie True si et seulement si les deux structures sont compatibles.
def compatibles(p, f):bksl-nl """ Pile, File -> Boolbksl-nl Détermine si les chapeaux sont associés aux bon bonshommes """bksl-nl passbksl-nlbksl-nl
Le problème de la mutabilité et solution du problème¶
- Afficher le contenu des piles
p1etf1après exécution de la fonctioncompatibles. - Que constate-t-on ? À quoi cela est-il dû ?
- Quel problème cela va-t-il éventuellement poser ?
Modification de la fonction compatibles¶
On souhaite modifier le code de la fonction compatibles afin qu'à la fin de l'exécution de l'instruction compatibles(p, f), les piles p et f soient dans le même état qu'au début.
Pour cela, lors de l'exécution de la fonction compatibles, à chaque dépilement (resp. défilement) de la pile p (resp. f) on empilera le chapeau c (resp. enfilera le bonhomme b) obtenu dans une pile pile_aux (resp. une file file_aux), et on s'assurera de restaurer l'état initial avant toute instruction return.
On écrira pour cela une fonction restaure_pile(p, p_aux) (resp. restaure_file(f, f_aux)) restaurant l'état initial de p à l'aide de p_aux (resp. f à l'aide de f_aux). On donne ci-dessous un schéma explicatif de l'algorithme de la fonction restaure_pile. Une idée similaire est à adapter pour la fonction restaure_file.

def restaurepy-undpile(p, ppy-undaux):bksl-nl """ Pile, Pile -> Nonebksl-nl Restaure p à son état initial lorsque les dépilements successifsbksl-nl on été empilés dans ppy-undaux. """bksl-nl while not p.estpy-undvide():bksl-nl c = p.depiler()bksl-nl ppy-undaux.empiler(c)bksl-nl while not ppy-undaux.estpy-undvide():bksl-nl # À compléterbksl-nlbksl-nldef restaurepy-undfile(f, fpy-undaux):bksl-nl """ File, File -> Nonebksl-nl Restaure f à son état initial lorsque les défilement successifsbksl-nl on été enfilés dans fpy-undaux. """bksl-nl passbksl-nlbksl-nldef compatibles(p, f):bksl-nl """ Pile, File -> Boolbksl-nl Détermine si les chapeaux sont associés aux bons bonshommesbksl-nl L'état de la pile p et la file f sera le même avant et après exécution """bksl-nl passbksl-nlbksl-nl
def restaurepy-undpile(p, ppy-undaux):bksl-nl """ Pile, Pile -> Nonebksl-nl Restaure p à son état initial lorsque les dépilements successifsbksl-nl on été empilés dans ppy-undaux. """bksl-nl while not p.estpy-undvide():bksl-nl c = p.depiler()bksl-nl ppy-undaux.empiler(c)bksl-nl while not ppy-undaux.estpy-undvide():bksl-nl # À compléterbksl-nlbksl-nldef restaurepy-undfile(f, fpy-undaux):bksl-nl """ File, File -> Nonebksl-nl Restaure f à son état initial lorsque les défilement successifsbksl-nl on été enfilés dans fpy-undaux. """bksl-nl passbksl-nlbksl-nldef compatibles(p, f):bksl-nl """ Pile, File -> Boolbksl-nl Détermine si les chapeaux sont associés aux bons bonshommesbksl-nl L'état de la pile p et la file f sera le même avant et après exécution """bksl-nl passbksl-nlbksl-nl
Calcul de la solution du problème¶
Écrire une fonction solution qui renvoie la liste des couples solution au problème.
Par exemple, si la pile de chapeau numéro 1 correspond à la file de bonhomme de neige 2, alors on ajoutera l'entrée (1, 2) à la liste des couples solution.
def solution():bksl-nl """ () -> [(int, int)]bksl-nl Renvoie la liste des associations pile i <-> file j """bksl-nl piles = initpy-undpiles()bksl-nl files = initpy-undfiles()bksl-nl sol = []bksl-nl # À compléterbksl-nlbksl-nl
Une rampe de billes¶
Sur une rampe, il y a 10 billes numérotées dans l'ordre. Le long de la rampe, il y a trois trous \(A\), \(B\) et \(C\) : le trou \(A\) peut contenir trois billes au maximum, le trou \(B\) deux billes et le trou \(C\) une seule bille au maximum.
Quand les billes roulent sur la rampe, elles tombent successivement dans les trous jusqu'à ce qu'elles les remplissent (les billes 1, 2 et 3 tombent dans le trou \(A\), les billes 4 et 5 tombent dans le trou \(B\) et la bille 6 tombe dans le trou \(C\)). Les autres billes passent par-dessus et continuent leur chemin jusqu'à la fin de la rampe.
Quand toutes les billes ont parcouru la rampe, les ressorts, placés dans les trous \(A\) à \(C\), éjectent les billes qu'ils contenaient : d'abord, les trois billes du trou \(A\), ensuite, celles du trou \(B\) et finalement, celle du trou \(C\). Les billes sont ainsi poussées sur la rampe. On attend que toutes les autres billes aient passé avant qu'un ressort ne soit relâché.

- Dans quel ordre les billes de la séquence 1 à 10 seront-elles alignées à la fin ?
-
Sur une installation du même type, dix billes initialement ordonnées de 1 à 10 sur la rampe arrivent dans l'ordre : 8, 9, 10, 4, 3, 2, 1, 5, 7, 6.
Combien de trous y avait-il sur le parcours, et quelle est leur profondeur ? On justifiera la réponse. 3. Compléter la fonction
arrivee_rampe(profondeurs)qui prend en paramètre une liste d'entiers donnant la profondeur de chacun des trous sur une installation du même type que celle vue précédemment, dans l'ordre dans lequel ils sont positionnés sur le parcours, et qui renvoie la liste des entiers 1 à 10, dans l'ordre dans lequel les billes 1 à 10 arriveraient sur la rampe.On utilisera pour cela les classes
PileetFiledéfinies précédemment. Ces classes ont toutes les deux été enrichies d'un attributmax_eltet d'une méthodeest_pleinequi renvoieTruesi et seulement si la pile (resp. file) contientmax_eltéléments. Lors d'un empilement (resp. enfilement), on vérifie d'abord que la pile (resp. file) n'est pas pleine. Si la pile (resp. file) est pleine, alors on soulève une exception. On appelle ce genre de pile (resp. files) des piles (resp. files) bornées.Fonction Signature Description Pile(max_elt = n)int -> PileRenvoie une pile bornée de capacité maximale np.est_pleine()() -> BoolDétermine si la pile a atteint sa capacité maximale. File(max_elt = n)int -> FileRenvoie une file bornée de capacité maximale nf.est_pleine()() -> BoolDétermine si la file a atteint sa capacité maximale.
def arriveepy-undrampe(profondeur):bksl-nl """ [int] -> [int]bksl-nl Détermine l'ordre d'arrivée des boules numérotées de 1 à 10 """bksl-nl rampepy-undlancement = File()bksl-nl for b in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:bksl-nl ... # à compléterbksl-nl piles = [Pile(maxpy-undelt = p) for p in profondeur] # liste de piles bornées, dans l'ordre du parcours.bksl-nl rampepy-undfinale = File() # billes dans l'ordre d'arrivéebksl-nl numeropy-undpile = 0 # indice de la pile à remplirbksl-nl bksl-nl # on remplit les piles dans l'ordre dans lequel elles sontbksl-nl # positionnées sur le parcours tant que cela est possiblebksl-nl # (c'est à dire tant que la dernière pile du parcours n'est pas vide)bksl-nl # Si la pile que l'on cherche à remplir est pleine,bksl-nl # alors il faut commencer par changer le numéro de la pile à remplir. bksl-nl # On empile une bille prise depuis la rampe de lancement sur la pile à remplir.bksl-nl while ...:bksl-nl ... # à compléterbksl-nl bksl-nl # Toutes les billes restantes roulent directement dans la rampe d'arrivée.bksl-nl while ...:bksl-nl ... # à compléterbksl-nl bksl-nl # On retire les ressorts dans l'ordre dans lesquels ils sontbksl-nl # positionnés sur le parcours. Les billes ressortent des trous etbksl-nl # viennent s'accumuler sur la rampe de lancement.bksl-nl for p in piles:bksl-nl while ...:bksl-nl ... # à compléterbksl-nlbksl-nl return rampepy-undfinalebksl-nlbksl-nl
Conclusion¶
En anglais, l'acronyme FILO signifie Firt In Last Out (premier entré dernier sorti), et l'acronyme FIFO signifie Fist In First Out (premier entré premier sorti).
Quel acronyme peut s'appliquer à une pile ? À une file ?