"""
    ---------------------
        PARTIEL BLANC
    ---------------------

    Petite correction commentée.
"""


""" -----  Exercice 1  ----- """
print("\n----- EXERCICE 1 -----\n")


x = 69  # Variable globale qui n'est modifié
        # qu'avec un le mot clé "global"
        # dans une fonction

def magic(x):    
    x = x + 42  # x ici est une copie locale,
                # l'affectation se fait donc sur la copie
                # et ne modifie par globalement x

magic(x) # La fonction ne fait rien globalement
print("x vaut", x)  # Affichera "x vaut 69"


""" POUR LA SUITE DES EXOS """


import numpy as np


""" -----  Exercice 2  ----- """
print("\n----- EXERCICE 2 -----\n")


def newton(x_depart):
    """
    Fonction permettant de résoudre l'équation
        f(x) = -cosh(x) + x² = 0

    On utilise x = 0.5 et x = 1 pour les valeurs de départ
    
    f(x) = -cosh(x) + x²
    f'(x) = -sinh(x) + 2x
    """

    x = x_depart              # On définit notre variable de départ
    f_x = -np.cosh(x) + x * x   # On calcule l'image de f en x
    df_x = -np.sinh(x) + 2 * x  # On calcule l'image de f' en x

    # On continue jusqu'à trouver un résultat suffisamenent proche
    while np.abs(f_x) > 1e-5 and df_x != 0:
        x = x - f_x / df_x          # On calcule le prochain x
        f_x = -np.cosh(x) + x * x   # Comme au dessus
        df_x = -np.sinh(x) + 2 * x  # idem
    
    return x

# Affichage du résultat
for i in [0.5, 1]:
    print("x_s =", i, "=> x =", newton(i))


""" -----  Exercice 3  ----- """
print("\n----- EXERCICE 3 -----\n")


def tasser(tableau, taille_tableau):
    """
    Fonction permettant de tasser un tableau
    
    Exemple :
    [0, 1, 0, 0, 2, 3] => [1, 2, 3, 0, 0, 0]

    Detail des permutations :
     -> o indice du dernier element nul
     -> c indice du curseur
     oc                    o  c
    [0, 1, 0, 0, 2, 3] => [1, 0, 0, 0, 2, 3]
                              o        c
                       => [1, 2, 0, 0, 0, 3]
                                 o        c
                       => [1, 2, 3, 0, 0, 0]
    
    Fin du programme :
              o        c
    [1, 2, 3, 0, 0, 0]
    """

    curseur_principal = 0   # On initialise le curseur qui
                            # permet de parcourir le tableau
    dernier_non_nul = 0 # On initialise le curseur vers le
                        # dernier élément nul du tableau

    # Tant qu'il reste des éléments à regarder
    while curseur_principal < taille_tableau:
        # On trouve un élément non nul
        if tableau[curseur_principal] != 0:
            # Si les curseurs sont au même endroit
            # On ne fait pas de permutation inutile
            if curseur_principal != dernier_non_nul:
                # On ramene la valeur non nulle sur la derniere valeur nulle
                tableau[dernier_non_nul] = tableau[curseur_principal]
                # On met un zero là ou était la valeur non nulle
                tableau[curseur_principal] = 0
            
            # On incrémente le curseur sur valeur nulle pour les prochaines permutations
            dernier_non_nul += 1
        
        # On incrémente le curseur "global"
        curseur_principal += 1
    
    return taille_tableau - dernier_non_nul
    

# Valeur de test pour visualiser le résultat
test_tasser = np.array([0, 0, 1, 2, 5, 0, 6, 0, 0, 9])
print(test_tasser)
print(tasser(test_tasser, 10))
print(test_tasser)


""" -----  Exercice 4  ----- """
print("\n----- EXERCICE 4 -----\n")


def executer(circuit, largeur, hauteur):
    """
    Fonction permettant l'exécution d'un
    circuit quelconque passé en paramètre.

    La difficulté de cet exercice repose essentiellement
    dans la compréhension du sujet et dans le choix du
    signe des indices de déplacement.
    """

    x_courant = 0   # Condition initiale : position (0, 0)
    y_courant = 0   # Condition initiale : position (0, 0)
    direction = 2   # Condition initiale : vers la droite

    # On continue tant que le courant est dans le circuit
    while 0 <= x_courant < largeur and 0 <= y_courant < hauteur:
        composant = circuit[y_courant, x_courant]

        # On s'occupe des composantes directions
        # Qui sont des chiffres (type int donc)
        if type(composant) == int and 1 <= composant <= 4:
            direction = composant

        # On affiche la lettre si n'est pas sur un 0
        elif composant != 0:
            print(composant, end="")
        
        # On avance dans la bonne direction
        if direction == 1:      # Haut
            y_courant -= 1
        elif direction == 2:    # Droite
            x_courant += 1
        elif direction == 3:    # Bas
            y_courant += 1
        elif direction == 4:    # Gauche
            x_courant -= 1


# Bonus, un circuit possible
circuit_banane = np.array(
    [
        [ 0, 'B', 3,  0],
        [ 0,  2, 'a', 3],
        ['e', 0, 'n', 4],
        [ 0,  1,  4,  0],
    ],
dtype="O")
executer(circuit_banane, 4, 4)

print("\n")
