Aller au contenu

E02 - Escalier⚓︎

Le problème

Escalier

Proposition 1⚓︎

🐍 Script Python
hauteur_marche = int(input())
for x in range(hauteur_marche + 1): # +1 car la hauteur_marche est enclux 
    print("X" * x)
  • Une fonction est attendue.
  • x : nom de variable peu clair.
  • hauteur_marche : nom de variable peu clair.
  • "X" * x : facilité du langage non recommandée ici.
  • Il y a un saut de ligne en trop au début, avec x = 0. C'est accepté par le juge Prologin, mais uniquement en début et en fin de la sortie complète.

Proposition 2⚓︎

🐍 Script Python
def escalier(nb_marches : int):
    """ Prend un entier "nb_marches" et renvoie un escalier de "nb_marches", rempli du caractère "X" de manière récursive.
    """
    if nb_marches == 0:
        return ""
    else:
        return escalier(nb_marches -1) + "\n" + "X" * nb_marches

# tests
import doctest
doctest.testmod()

# Entrée
nb_marches = int(input())

# Sortie
print(escalier(nb_marches))
  • Bien, mais il n'y a pas de tests pour le doctest ; il y avait en effet une difficulté avec ce problème.
  • Ce programme affiche un saut de ligne en trop au début.
  • Il faut éviter les longues lignes, même en docstring.

Proposition 3⚓︎

🐍 Script Python
def triangle(nombre_marche):
    """ Cette fonction prend en paramètre un entier positif et elle affiche un escalier, rempli du caractère X.

    >>> triangle(4)
    X
    XX
    XXX
    XXXX

    """
    for i in range(1,nombre_marche+1,1):
        print(i*"X")

# tests
import doctest
doctest.testmod()

# Entrée
nombre_marche = int(input())

# Sortie
triangle(nombre_marche)
  • range(1,nombre_marche+1,1)
    • On attend une espace après chaque virgule.
    • On attend une espace avant et après +.
    • Le troisième paramètre est inutile.
    • nb_marches est un meilleur nom de variable.
  • Éviter les longues lignes ; 80 caractères maximum.

Proposition 4⚓︎

🐍 Script Python
def triangle(nb_marches : int): 
    """Renvoie un triangle rectangle à la hauteur demandé.
    >>> triangle(4)
    X 
    XX 
    XXX 
    XXXX 
    """
    if nb_marches == 0:
        return ""
    else:
        return triangle(nb_marches-1) + "\n" + "X"*nb_marches

# Test (Ne fonctionne pas)
#import doctest
#doctest.testmod() 

# Entrée
nb_marches = int(input())

# Sortie
print(triangle(nb_marches))
  • Le doctest ne fonctionne pas, en effet la fonction n'affiche pas l'escalier, mais le renvoie.
  • Aérer le doctest !
  • Cette version récursive renvoie un saut de ligne en trop au début.

Proposition 5⚓︎

🐍 Script Python
nombre_marches = int(input())
escalier = ""

def donne_ligne(longueur: int) -> str:
    """
    Renvoie une chaine de charactères correspondant à "X" fois  `longueur`
    et le rajout, à la fin de `\n`
    >>> donne_ligne(5)
    'XXXXX\n'
    >>> donne_ligne(0)
    ''
    """
    ligne = "".join("X" for _ in range(longueur))
    return ligne + "\n"

for hauteur in range(nombre_marches):
    escalier += donne_ligne(hauteur+1)

print(escalier)
  • Un "".join pour une valeur constante dans l'itérateur... autant utiliser "X" * longueur.
  • La fonction donne_ligne devrait plutôt être placée avant la lecture de l'entrée.
  • Une fonction pour l'escalier aurait été bien aussi.
  • Aérer le doctest.

Proposition 6⚓︎

🐍 Script Python
# 0- Coeur du programme

def construire_escalier(nb_marches: int) -> str:
    """ Renvoie un escalier de hauteur nb_marches rempli du caractère "X".
    >>> construire_escalier(1)
    'X\\n'
    >>> construire_escalier(5)
    'X\\nXX\\nXXX\\nXXXX\\nXXXXX\\n'
    """

    if nb_marches == 1:
        return("X\n" )
    else:
        return(construire_escalier(nb_marches-1) + "X"*nb_marches + "\n")

# 1- Tests

import doctest
doctest.testmod()

# 2- Lecture de l'entrée

nb_marches = int(input())

# 3- Appel de la fonction / Sortie

print(construire_escalier(nb_marches))
  • doctest à aérer.
  • C'est bien, il fallait échapper les contre-obliques avec cette méthode ; c'est correct, mais lourd et peu pertinent de renvoyer l'escalier... Une autre solution était de placer un r avant le triple double guillemet entrant, pour rendre la chaine brute (raw en anglais) où les caractères ne sont pas échappés.
  • Cette version récursive n'ajoute pas de saut de ligne en trop au début ; c'est bien !

Proposition 7⚓︎

🐍 Script Python
def escalier(nb_marches : int) -> str : 
    """ Renvoie 'nb_marches' lignes avec sur chaque ligne 
    le même nombre de caractere "X" que la nième ligne.

    >>> nb_marches = 4
    >>> escalier(nb_marches)
    X
    XX
    XXX
    XXXX

    """    
    assert 1 < nb_marches < 200
    for marche in range (nb_marches):
        print ('X' * (marche + 1))

# tests
import doctest
doctest.testmod()

# Entrée
nb_marches = int(input())

# Sortie
escalier(nb_marches)
  • La docstring indique 'renvoie', mais la fonction 'affiche' l'escalier. Également l'annotation de type -> str est fausse ici.
  • Le assert est inutile ici ; un élève doit faire confiance aux données fournies par un juge en ligne.
  • Le doctest est ici valide.

Corrigé du professeur⚓︎

🐍 Script Python
"""
author: Franck CHAMBON
problem: https://prologin.org/train/2003/semifinal/escalier
"""

def affiche_escalier(nb_marches: int) -> None:
    """Affiche un escalier qui a `nb_marches`.

    >>> affiche_escalier(4)
    X
    XX
    XXX
    XXXX

    """
    for largeur in range(1, nb_marches + 1):
        for _ in range(largeur):
            print("X", end="")
        print()
    return


# Tests

import doctest
doctest.testmod()


# Entrée / Sortie

nb_marches = int(input())
affiche_escalier(nb_marches)

Variante fonctionnelle⚓︎

🐍 Script Python
def affiche_escalier(nb_marches: int) -> None:
    print("\n".join("X" * i for i in range(1, nb_marches + 1)))

Variante récursive⚓︎

🐍 Script Python
def affiche_escalier(nb_marches: int) -> None:
    if nb_marches > 0:
        affiche_escalier(nb_marches - 1)  # le début de l'escalier
        print("X" * nb_marches)           # la dernière ligne

Commentaires⚓︎

  • Ici, exceptionnellement, on intègre l'affichage dans la fonction.
    • Cela rend le doctest plus simple ; un saut de ligne en trop au début peut le rendre faux.
    • Obtenir l'escalier sous forme d'une seule chaine n'est pas très utile, à part pour l'afficher ; autant faire une fonction qui affiche.
  • Utiliser la multiplication de chaines comme x * "X" est à éviter ici ; on attendait une double boucle, et pas cette facilité du langage.

De manière générale, pour un problème simple, on demande de n'utiliser que des outils basiques. Pas d'utilisation de facilité du langage dans un problème simple ; on ne le contourne pas. Ensuite, pour un problème avec d'autres difficultés, on peut naturellement utiliser les facilités du langage, sans qu'elle ne ruine le problème. Encore une fois, la règle étant de ne pas contourner le problème. Enfin, en commentaire, on peut aussi proposer une version qui montre vos connaissances du langage.