"""
Séquence 1, Séance 2 — La liste comme interface (implémentation avec des
tuples imbriqués)
=============================================================================

Ce fichier correspond à la section « La liste vue comme une interface » de
la fiche « Interfaces, implémentation bas niveau et POO ».

Il contient :
  - le code du cours (creer_liste, ajouter_en_tete, tete, queue, est_vide) ;
  - le code des Exercices 4 et 5 (nombre_element, val, est_dans) ;
  - les tests correspondants.

Pour l'exécuter : télécharger ce fichier, puis dans un terminal, dans le
même dossier :
    python3 listes_interface.py

Si tout est correct, le programme affiche "Tests de la liste-interface : OK".
"""


def creer_liste():
    """Renvoie la liste vide."""
    return None


def ajouter_en_tete(x, L):
    """Insère l'élément x en tête de la liste L."""
    return (x, L)


def tete(L):
    """Renvoie l'élément de tête de L."""
    return L[0]


def queue(L):
    """Renvoie la liste L privée de son élément de tête."""
    return L[1]


def est_vide(L):
    """Renvoie True si L ne contient aucun élément."""
    return L is None


def nombre_element(L):
    """Nombre d'éléments d'une liste : 0 si vide, sinon 1 + le nombre
    d'éléments de sa queue."""
    if est_vide(L):
        return 0
    else:
        return 1 + nombre_element(queue(L))


def val(i, L):
    """Élément de rang i (0 = tête), en avançant i fois avec queue."""
    assert not (i < 0 or i > nombre_element(L)), "index hors limite"
    compteur = 0
    temp_liste = L
    while compteur < i:
        temp_liste = queue(temp_liste)
        compteur += 1
    return tete(temp_liste)


def est_dans(x, L):
    """Vrai si x est un élément de la liste L, faux sinon."""
    if est_vide(L):
        return False
    else:
        if x == tete(L):
            return True
        else:
            return est_dans(x, queue(L))


def test_exercice_4():
    """Exercice 4 : créer la liste des voyelles et accéder à la voyelle 'i'."""
    L2 = creer_liste()
    for voyelle in ['y', 'u', 'o', 'i', 'e', 'a']:
        L2 = ajouter_en_tete(voyelle, L2)

    assert L2 == ('a', ('e', ('i', ('o', ('u', ('y', None))))))
    assert tete(L2) == 'a'
    assert tete(queue(queue(L2))) == 'i', "la 3e voyelle (rang 2) doit être 'i'"

    print("Exercice 4 : OK")


def test_exercice_5():
    """Exercice 5 : écrire nombre_element, val, et étudier est_dans."""
    L2 = creer_liste()
    for voyelle in ['y', 'u', 'o', 'i', 'e', 'a']:
        L2 = ajouter_en_tete(voyelle, L2)

    assert nombre_element(L2) == 6
    assert val(0, L2) == 'a'
    assert val(2, L2) == 'i'
    assert val(5, L2) == 'y'

    assert est_dans('o', L2) is True
    assert est_dans('z', L2) is False

    print("Exercice 5 : OK")


if __name__ == "__main__":
    test_exercice_4()
    test_exercice_5()
    print("Tests de la liste-interface : OK")
