On s'entraîne à coder de petits projets

Quelques exercices pour se mettre le code dans les pattes. Pour chacun des projets vous ferez 2 fichiers :

Chaque sujet contient son corrigé, mais faites dans l'ordre :

Pour chaque sujet

  1. faites tous les exercices
  2. regardez les erreurs courantes et corriger si besoin votre projet
  3. comparez votre code au corrigé

Syracuse

On essaye d'écrire un programme qui teste la conjecture de Syracuse pour des entiers.

Questions

Écrivez une fonction syracuse telle que :

  • entrée : un entier $x$
  • sortie :
    • $x/2$ si $x$ est pair
    • $3x + 1$ si $x$ est impair

En utilisant le fait que le modulo s'écrit % en python.

corrigé

def syracuse(x):
    if x % 2 == 0:
        return x / 2
    else:
        return 3 * x + 1

Écrivez une fonction qui rend tous les éléments de la suite de Syracuse associée à un nombre

  • entrée : un entier $x$
  • sortie : les élément de la suite de Syracuse associée à $x$

La suite de Syracuse est définie telle que :

  • $u_0 =x$
  • $u_{n+1} = \mbox{syracuse}(u_n)$
  • on s'arrête lorsque $u_n =1$

corrigé

def suite(u_0):
    sortie = [u_0]

    u_n = u_0
    while u_n != 1:
        u_n = syracuse(u_n)
        sortie.append(u_n)

    return sortie

Écrivez le programme principale qui demande à l'utilisateur de taper un nombre et rend la suite de Syracuse de ce nombre.

  • vous supposerez que l'utilisateur ne se trompe pas (pas besoin de gérer ses erreurs potentielles)
  • vous utiliserez la fonction input() qui rend une chaîne de caractères tapée par l'utilisateur
  • int(x) est l'entier représenté par la chaîne de caractère x.

corrigé

from syracuse import suite

sortie_utilisateur = input("Donnez un entier : ")

u_0 = int(sortie_utilisateur)

print("suite de Syracuse associée : ", suite(u_0))

Corrigé détaillé

  1. Erreurs courantes à éviter
  2. Le programme final

Jeu du pendu

On essaye d'écrire un programme qui joue au jeu du pendu.

Questions

Écrire la fonction est_une_lettre(lettre, mot) telle que :

  • paramètres d'entrée :
    1. lettre un caractère
    2. mot une chaîne de caractères
  • sortie :
    • si au moins une des lettres de mot et lettre, la fonction rend True
    • sinon, la fonction rend False
  • exemples :
    • est_une_lettre("i", "victoire") doit rendre True
    • est_une_lettre("e", "la disparition") doit rendre False

corrigé

Plusieurs possibilités. Commençons par la plus simple, que tout le monde devrait arriver à faire, c'est une retranscription directe d'un algorithme du cours :

def est_une_lettre(lettre, mot):
    for c in mot:
        if lettre == c:
            return True
    return False

On pouvait aussi utiliser le mot clé in de python (supposé connu de tous), pour une solution écrite en 30 secondes chrono :

def est_une_lettre(lettre, mot):
    if lettre in mot:
        return True
    else:
        return False

Notez que la version précédente est identique à la version ci-dessous, bien plus élégante :

def est_une_lettre(lettre, mot):
    return lettre in mot

Écrire la fonction caractères(lettre, mot) telle que :

  • paramètres d'entrée :
    1. lettre un caractère
    2. mot une chaîne de caractères
  • sortie :
    • une liste $L$ contenant tous les indices des caractères de mot qui valent lettre. Cette liste doit être triée par ordre croissant.
  • exemples :
    • caractères("i", "victoire") doit rendre [1, 5]
    • caractères("e", "la disparition") doit rendre []

corrigé

def caractères(lettre, mot):
    position = []

    for i in range(len(mot)):
        if mot[i] == lettre:
            position.append(i)

    return position

On utilise ici la fonction range pour itérer sur les indices du tableau plutôt que sur ses valeurs.

Encore une fois, tout le monde devrait arriver à faire cette fonction d'une seule traite, sans réfléchir.

Écrire la fonction découvre(mot_caché, lettre, positions) telle que :

  • paramètres d'entrée :
    1. mot_caché une chaîne de caractères
    2. lettre un caractère
    3. positions une liste d'entiers rangés par ordre croissant
  • sortie :
    • la chaîne de caractères mot_caché où les indices correspondants aux entiers de positions sont remplacés par lettre
  • exemples :
    • découvre("......", "r", [1, 2, 5]) doit rendre ".rr..r"
    • découvre("erre.r", "u", [4]) doit rendre "erreur"
    • découvre("erre.r", "u", []) doit rendre "erre.r"

corrigé

La fonction que j'attends est :

def découvre(mot_caché, lettre, positions):
    mot = ""

    for i in range(len(mot_caché)):
        if i in positions:
            mot += lettre
        else:
            mot += mot_caché[i]

    return mot

En utilisant les caractéristiques de la liste positions trié par ordre croissant, on aurait pu forger la fonction ci-dessous de complexité $\mathcal{O}(n)$ (pourquoi est-ce que ça marche ?):

def découvre(mot_caché, lettre, positions):
    mot = ""

    if len(positions) == 0:
        return mot_caché

    pos = 0
    for i in range(len(mot_caché)):
        if i == positions[pos]:
            mot += lettre
            pos = min(pos + 1, len(positions) - 1)
        else:
            mot += mot_caché[i]

    return mot

Écrire la fonction caché(mot) telle que :

  • paramètres d'entrée :
    1. mot une chaîne de caractères
  • sortie :
    • une chaîne de caractères composée uniquement de "." et de longueur égale à celle de mot
  • exemples :
    • caché("anticonstitutionnellement") doit rendre "........................."
    • caché("") doit rendre ""

corrigé

En utilisant la multiplications des chaînes de caractères, la fonction est triviale :

def caché(mot):
    return "." * len(mot)

Créez un programme principal permettant de jouer au pendu jusqu'à ce que le mot à trouver ne contienne plus de "."

corrigé

Une proposition de programme principal :

    mot_à_trouver = "table"
    mot_caché = caché(mot_à_trouver)

    print("mot à trouver :", mot_caché)
    nombre_essai = 0

    while est_une_lettre(".", mot_caché):
        lettre = input("Donnez une lettre : ")
        mot_caché = découvre(mot_caché, lettre, caractères(lettre, mot_à_trouver))
        print("mot à trouver :", mot_caché)

        nombre_essai += 1

    print("Victoire !, vous avez gagné en", nombre_essai, "essais.")

Corrigé détaillé

  1. Erreurs courantes à éviter
  2. Le programme final

Le compte est bon

Le programme consiste à demander à l'utilisateur une chaîne de caractères et un caractère. On cherchera à savoir combien de fois apparaît le caractère dans la chaîne. On va créer le programme en ajoutant petit à petit des fonctionnalités au programme.

Questions

Créer un fichier main.py permettant d'exécuter les 4 étapes de l'algorithme suivant :

  1. Demander à l'utilisateur une chaîne de caractères que l'on nommera chaîne_entrée (en utilisant la fonction input([prompt: str]) -> str)
  2. Demander à l'utilisateur un caractère que l'on nommera caractère_entrée (vous ne ferez aucune vérification de type)
  3. Afficher à l'écran le plus petit indice (ou -1) de chaîne_entrée valant caractère_entrée (vous pourrez utiliser la méthode find des chaînes de caractères)
  4. Retournez à l'étape 1. de cet algorithme à part si chaîne_entrée valait "sortie"

corrigé

Fichier main.py :

chaîne_entrée = ""

while chaîne_entrée != "sortie":
    chaîne_entrée = input("Entre une chaîne de caractères : ")
    caractère_entrée = input("Entre un caractère : ")

    index_caractère = chaîne_entrée.find(caractère_entrée)
    print("Premier index du caractère :", index_caractère)

On veut savoir si le caractère caractère_entrée apparaît plusieurs fois dans la chaîne chaîne_entrée. Comme on connaît déjà le premier indice où il apparaît, on cherche s'il apparaît aussi plus tard.

Créer la fonction donne_prochain_indice(chaîne:str, indice:int) -> int qui rend :

  • Le plus petit indice $j$ strictement plus grand que le paramètre indice tel que chaîne[j] == chaîne[indice],
  • None si cet indice n'existe pas.

corrigé

def donne_prochain_indice(chaîne, indice):
    possible_suivant = chaîne.find(chaîne[indice], indice + 1)

    if possible_suivant > -1:
        return possible_suivant
    return None

Dans l'étape 3. de l'algorithme du programme principal, utilisez la fonction que vous venez de coder pour ajouter un affichage qui indique si caractère_entrée apparaît plusieurs fois dans chaîne_entrée ou pas.

L'étape 3. du programme principal sera alors constitué de deux actions :

  • Afficher à l'écran le plus petit indice (ou -1) de chaîne_entrée valant caractère_entrée (vous pourrez utiliser la méthode find des chaînes de caractères) (question 1)
  • Afficher si caractère_entrée est présent plus d'une fois dans chaîne_entrée (question 2)

corrigé

On ajoute à la fin du fichier main.py les lignes suivantes, dans le bloc while :

    if index_caractère == -1:
        print("Il n'apparaît pas")
    elif donne_prochain_indice(chaîne_entrée, index_caractère) != None:
        print("Il apparaît plusieurs fois")
    else:
        print("Il apparaît une fois")

On veut finalement savoir combien de fois apparaît caractère_entrée dans la chaîne chaîne_entrée. Comme on connaît sa première position grace à la question 1 et qu'on peut connaître la suivante grace à la question 2, on va terminer le boulot et compter combien de fois apparaît caractère_entrée dans chaîne_entrée.

Créer la fonction compte_caractère(chaîne: str, indice: int) -> int qui rend le nombre de fois où le caractère chaîne[indice] est présent dans le paramètre chaîne

corrigé

def compte_caractère(chaîne, indice):
    compte = 0

    while indice != None:
        compte += 1
        indice = donne_prochain_indice(chaîne, indice)

    return compte

Dans l'étape 3. de l'algorithme du programme principal, utilisez la fonction que vous venez de coder pour ajouter un affichage qui indique le nombre de fois où caractère_entrée apparaît dans chaîne_entrée.

L'étape 3. du programme principal sera alors constitué de trois actions :

  • Afficher à l'écran le plus petit indice (ou -1) de chaîne_entrée valant caractère_entrée (vous pourrez utiliser la méthode find des chaînes de caractères) (question 1)
  • Afficher à l'écran si caractère_entrée est présent plus d'une fois dans chaîne_entrée (question 2)
  • Afficher à l'écran le nombre de fois où caractère_entrée apparaît dans chaîne_entrée (question 3)

corrigé

On ajoute à la fin du fichier main.py les lignes suivantes, dans le bloc while :

    if index_caractère > -1:
        nombre = compte_caractère(chaîne_entrée, index_caractère)
        print("Le caractère apparaît", nombre , "fois.")

Cerise sur le gateau, on cherche à savoir si caractère_entrée est le caractère qui apparaît le plus de fois dans chaîne_entrée.

Créer la fonction donne_max_doublon(chaîne: str) -> int qui rend le nombre maximum de fois où apparaît un même caractère dans chaîne.

corrigé

def donne_max_doublon(chaîne):
    nombre_max = 0

    for i in range(len(chaîne)):
        nombre_max = max(nombre_max, compte_caractère(chaîne, i))

    return nombre_max

Dans l'étape 3. de l'algorithme du programme principal, utilisez la fonction que vous venez de coder pour ajouter un affichage qui le nombre maximum de répétition d'un caractère, et affichez un message de victoire si caractère_entrée réalise ce maximum.

L'étape 3. du programme principal sera alors constitué de quatre actions :

  • Afficher à l'écran le plus petit indice (ou -1) de chaîne_entrée valant caractère_entrée (vous pourrez utiliser la méthode find des chaînes de caractères) (question 1)
  • Afficher à l'écran si caractère_entrée est présent plus d'une fois dans chaîne_entrée (question 2)
  • Afficher à l'écran le nombre de fois où caractère_entrée apparaît dans chaîne_entrée (question 3)
  • Afficher à l'écran le nombre maximum de répétition d'un caractère, et affichez un message de victoire si caractère_entrée réalise ce maximum. (question 4)

corrigé

On ajoute à la fin du fichier main.py les lignes suivantes, dans le bloc while :

    if index_caractère > -1:
        nombre = compte_caractère(chaîne_entrée, index_caractère)
        print("Le caractère apparaît", nombre, "fois.")

        if nombre == donne_max_doublon(chaîne_entrée):
            print("c'est le max !")

Corrigé détaillé

  1. Erreurs courantes à éviter
  2. Le programme final