Aller au contenu

E02 - Ancien parchemin⚓︎

Le problème

Ancien parchemin

Proposition 1⚓︎

🐍 Script Python
"""
Auteur : ********
https://prologin.org/train/2004/semifinal/ancien_parchemin
"""

def correspondance(nb_C_A, nb_C_P, texte_A, texte_P, indice_correspondance):
    """ Renvoie l'indice de correspondance, si le texte de l'assistant peut correspondre au texte du parchemin trouvé

    >>>correspondance(4, t?t?, 4, titi, 0)
    1

    >>>correspondance(11, kikoo lol ?, 11, Hello World, 0)
    0

    """

    if nb_C_A != nb_C_P:
        return "0"
    else:
        for i in range(nb_C_P):
            if texte_P[i] == "?":
                pass
            elif texte_A[i] == texte_P[i]:
                indice_correspondance = 1
            elif texte_A[i] != texte_P[i]:
                indice_correspondance = 0
                break
    return indice_correspondance


import doctest
doctest.testmod

# Entrée
nb_caractère_parchemin = int(input())
texte_parchemin = input()
nb_caractère_assistant = int(input())
texte_assistant = input() 

# Sortie
indice_correspondance = 0
print(correspondance(nb_caractère_assistant, nb_caractère_parchemin, texte_assistant, texte_parchemin, indice_correspondance))
  • Erreurs sur doctest
Diff
-    >>>correspondance(4, t?t?, 4, titi, 0)
+    >>> correspondance(4, "t?t?", 4, "titi", 0)
  • Avec Python, on préfère éviter de donner les longueurs des listes ou chaine ; c'est une habitude qui vient des vieux langages.

  • Tu pouvais utiliser un return à la place du break.

  • Tu pouvais ne pas utiliser pass.

  • Il y a des lignes trop longues.

Proposition 2⚓︎

🐍 Script Python
def correspondance(nb_parchemin,texte,nb_assistant,texte_assistant):
    if nb_parchemin == nb_assistant:
        for i in range(nb_parchemin-1):
            if texte[i] != "?":
                if texte[i] != texte_assistant[i]:
                   return 0
                else:
                   return 1
    else:
        return 0

nb_parchemin = int(input())
texte= input()
nb_assistant =  int(input())
texte_assistant= input()
print(correspondance(nb_parchemin,texte,nb_assistant,texte_assistant))

import doctest
doctest.testmod()
  • PEP-8 : De l'espace est souhaitée.
Diff
-correspondance(nb_parchemin,texte,nb_assistant,texte_assistant):
+correspondance(nb_parchemin, texte, nb_assistant, texte_assistant):
  • Mais aussi de meilleurs noms de variable.

  • Le return 1 est mal placé, il est prématuré. Il faut tester toutes les lettres avant de renvoyer 1. Et on préfère renvoyer True avec Python, on affichera 1 dans la partie affichage.

Proposition 3⚓︎

🐍 Script Python
def vérification(parchemin_a_déchifré, parchemin_assistant, nb_chr_parchemin_a_déchifré):
    """renvoie 1 si le parchemin de l'assistant concide avec celui
    a déchiffrer et 0 si il ne coincide pas

    >>>4
    >>>t?t?
    >>>4
    >>>titi
    1

    >>>11
    >>>kikoo lol ?
    >>>11
    >>>hello world
    0

    """
    if nb_chr_parchemin_a_déchifré == nb_chr_parchemin_assistant:
        for i in range(nb_chr_parchemin_a_déchifré):
            if i+1 == nb_chr_parchemin_a_déchifré:
                return 1
            elif (parchemin_a_déchifré[i] != parchemin_assistant[i]
            and parchemin_a_déchifré[i] != '?'):
                return 0
    else:
        return 0

nb_chr_parchemin_a_déchifré = int(input())
parchemin_a_déchifré = list(input())

nb_chr_parchemin_assistant = int(input())
parchemin_assistant = list(input())

print(vérification(parchemin_a_déchifré, parchemin_assistant, nb_chr_parchemin_a_déchifré))
  • C'est mieux de renvoyer un booléen, True ou False, et ensuite d'afficher 0 ou 1 selon... Avec de vieux langages, comme le C, on aurait renvoyé, oui c'est vrai, 0 ou 1... Pas avec Python.
  • Revoir les doctests
  • Ton test if i+1 == nb_chr_parchemin_a_déchifré: témoigne que tu sembles avoir copié une solution dans un autre language. Ceci est impossible en Python.
  • La fonction ne renvoie pas 1 dans tous les bons cas... Elle renvoie None à la fin de la boucle...

Proposition 4⚓︎

🐍 Script Python
def correspondance_parchemin(long_parchemin: int, parchemin: str, long_traduction: int, traduction: str) -> int:
    """
    Renvoie 0 si la traduction apporté par l'assistant correspond au parchemin

    >>> correspondance_parchemin(3, "a?c", 3, "abc")
    1

    >>> correspondance_parchemin(4, "a?cd", 5, "abcde")
    0

    """

    i = 0
    if long_parchemin > long_traduction or long_traduction > long_parchemin:    # pour vérifier si il ont les mêmes nombre de caractères
        return 0
    for lettre in parchemin:
        if lettre == traduction[i] or lettre == "?":
            i += 1
            pass
        else:
            return 0
    return 1


# Test

import doctest
doctest.testmod()

# Entrée

long_parchemin = int(input())
parchemin = input()
long_traduction = int(input())
traduction = input()

# Sortie

print(correspondance_parchemin(long_parchemin, parchemin,long_traduction, traduction))
  • On peut tester directement si deux nombres sont différents avec !=
  • Le i était inutile.
  • Tu pouvais éviter le pass (comme presque toujours).
  • Renvoyer un booléen est mieux que 0 ou 1, habitude qui vient des vieux langages...

Proposition 5⚓︎

🐍 Script Python
def compare(liste1: list, liste2: list) -> bool:
    """
    Cette fonction indique si les deux textes correspondent, 
    c'est à dire que tous les caractères visibles du texte du parchemin
    (différents de '?') sont identiques aux caractères correspondants du texte de l'assistant.

    >>> compare("t?t?","titi")
    True

    >>> compare("kikoo lol ?","hello world")
    False
    """
    if  len(liste1) != len(liste2):
        return False
    for lettre1, lettre2 in zip(liste1, liste2):
        if lettre1 != "?":
            if lettre1 != lettre2:
                return False
    return True

# Entrée 
import doctest
doctest.testmod()
nombre_caractères_texte_parchemin = int(input())
texte_parchemin = input()
nombre_caractères_texte_fourni_par_lassistant = int(input())
texte_assisant = input()

# Sortie
#print(1 if(compare(texte_parchemin, texte_assisant)) else 0)
#print(int(compare(texte_parchemin, texte_assisant)))
print(["0", "1"][compare(texte_parchemin, texte_assisant)])
  • Presque parfait.
  • Les identifiants pourraient être un peu meilleurs.
  • L'annotation de type est fausse, str au lieu de list.
  • Des trois possibilités de sortie que tu proposes, la dernière est la pire, il y a un transtypage implicite de compare(...) qui est un booléen vers un indice attendu entier. INTERDIT en NSI ! Et c'est mal ! La meilleure solution est la première ; tout le monde peut la comprendre. La seconde est acceptable.

Proposition 6⚓︎

🐍 Script Python
def Ancien_parchemin(nb_caractre_parchemin, text_parchemin, text_assistante):
    """
    Renvoie True ou False, si les caractere du parchemin corsepond ou pas avec celui de l'assitance
    """
    if text_parchemin[0] == text_assistante[0] or text_parchemin[0] == '?':
        if nb_caractre_parchemin == 1:
            return True
        else:
            return Ancien_parchemin(nb_caractre_parchemin-1, text_parchemin[1:], text_assistante[1:])
    else:
        return False

#Entrée
nb_caractre_parchemin = int(input())
text_parchemin = input()
nb_caractre_text = int(input())
text_assistante = input()

#Sortie
if nb_caractre_text != nb_caractre_parchemin:
    print('0')
else:
    print('1' if Ancien_parchemin(nb_caractre_parchemin, text_parchemin, text_assistante) == True else '0')
  • Ne fonctionne pas avec des textes vides au départ, ils coïncident pourtant !!!
  • == True est inutile. Le test if truc == True: est équivalent à if truc:.
  • Sinon, très jolie récursive.

Proposition 7⚓︎

🐍 Script Python
lettres_en_commun = 0

def valabilité_déduction():
    """Renverra :
    -> 0 dans le cas où le texte de l'assistant de peut pas correspondre à celui du parchemin
    -> 1 dans le cas où le texte de l'assistant peut correspondre à celui du parchemin

    >>> 5
    >>> av?i?
    >>> 5
    >>> avoir
    1

    >>> 8
    >>> c?c?rico
    >>> 8
    >>> cocarico
    0

    >>> 9
    >>> finland???
    >>> 7
    >>> finlande
    0

    """

    global lettres_en_commun

    if nb_caractère_texte_parchemin != nb_caractère_déduction :
        return 0
    else :

        for i in range(nb_caractère_déduction):

            if texte_parchemin[i] == déduction[i] :
                lettres_en_commun += 1

            elif texte_parchemin[i] != déduction :

                if texte_parchemin[i] == '?':
                    lettres_en_commun += 1

                else : # si != de '?'
                    return 0
            else :
                return 0

        if lettres_en_commun == nb_caractère_déduction :
            return 1


nb_caractère_texte_parchemin, texte_parchemin, nb_caractère_déduction, déduction = int(input()), list(input()), int(input()), list(input())
print(valabilité_déduction())
  • Avec Python, on préfère renvoyer des booléens plutôt que 0 ou 1, c'était une habitude avec de vieux langages...
  • Inutile d'utiliser des variables globales ; ce n'est pas joli.
  • il manque [i] au déduction du elif.
  • le dernier else est inutile ; cas impossible.
  • tu pouvais ne pas utiliser le nombre de caractères en commun...
  • revoir le doctest.

Corrigé du professeur⚓︎

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

def correspond(texte_1: str, texte_2: str) -> bool:
    """texte_1 et texte_2 correspondent-ils ?

    >>> correspond("t?t?", "titi")
    True

    >>> correspond("kikoo lol ?", "hello world")
    False

    """
    l_1 = len(texte_1)
    l_2 = len(texte_2)
    if l_1 != l_2:
        return False
    else:
        for c_1, c_2 in zip(texte_1, texte_2):
            if c_1 != '?':
                if c_1 != c_2:
                    return False
        return True

# Tests
import doctest
doctest.testmod()

# Entrée
l_1 = int(input())
texte_1 = input() # le parchemin
assert l_1 == len(texte_1)
l_2 = int(input())
texte_2 = input() # le texte de l'assistant
assert l_2 == len(texte_2)

# Sortie
print("1" if correspond(texte_1, texte_2) else "0")

Remarques

Le bout de code

🐍 Script Python
if c_1 != '?':
    if c_1 != c_2:
        return False

aurait pu s'écrire

🐍 Script Python
if (c_1 != '?') and (c_1 != c_2):
    return False

mais ici la première version semble plus limpide à comprendre. On préfèrera souvent la seconde, dans d'autres situations.

zip

🐍 Script Python
for c_1, c_2 in zip(texte_1, texte_2):
    ...

pourrait être remplacé par :

🐍 Script Python
longueur_commune = min(l_1, l_2)  # ici l_1 == l_2
for i in range(longueur_commune):
    c_1 = texte_1[i]
    c_2 = texte_2[i]
    ...