From 2abb1a30f83fa63c79a0460285e497ed2208ee0e Mon Sep 17 00:00:00 2001
From: Robin VAN DE MERGHEL <robin.van_de_merghel@etu.uca.fr>
Date: Wed, 26 Apr 2023 19:12:49 +0200
Subject: [PATCH] Adding old course of MRP

---
 Modeliser Resolution/houghman.py | 168 +++++++++++++++++++++++++++++++
 Modeliser Resolution/in.txt      |   6 ++
 2 files changed, 174 insertions(+)
 create mode 100755 Modeliser Resolution/houghman.py
 create mode 100755 Modeliser Resolution/in.txt

diff --git a/Modeliser Resolution/houghman.py b/Modeliser Resolution/houghman.py
new file mode 100755
index 0000000..569c79c
--- /dev/null
+++ b/Modeliser Resolution/houghman.py	
@@ -0,0 +1,168 @@
+"""Codage de Huffman.
+Cette verion est purement pédagogique et ne pourrait pas être de mise en
+production de manière efficace.
+Chaque étape donne lieu à des objets intermédiares qui peuvent être affichés,
+visualisés, contrôlés. 
+Cette version code des fichiers en UTF8 dont certains caractères sont codés sur
+un, deux, trois ou quatre octets."""
+
+
+def construit_liste_ss_arbres_caracteres_nombres(fichier, affiche=True):
+    """Pour chaque caractère c du fichier, constuit une liste :
+    [(c,n), None, None] où n est le nombre de fois que c est présent dans le
+    fichier. Une telle liste sera vue plus tard comme une feuille.
+    Si affiche == True, afficher les paires (c,n) dans l'ordre croissant de n.
+    """
+    characters = {}
+
+    with open(fichier, "r") as f:
+
+        for ligne in f.readlines():
+
+            for char in ligne:
+
+                if not char in characters:
+
+                    characters[char] = [(char, 1), None, None]
+
+                else:
+
+                    characters[char] = [
+                        (char, characters[char][0][1] + 1), None, None]
+
+    # On le transforme en liste
+
+    return [characters[key] for key in characters]
+
+
+def arbre_gauche(noeud):
+    return noeud[1]
+
+
+def arbre_droit(noeud):
+    return noeud[2]
+
+
+def est_feuille(noeud):
+    return arbre_gauche(noeud) == None and arbre_droit(noeud) == None
+
+
+def caractère(noeud):
+    """Retourne le caractère du noeud si le noeud est une feuille ;
+    retourne None sinon."""
+    if (est_feuille(noeud)):
+        return noeud[0][0]
+    return None
+
+
+def nb_caractères(noeud):
+    """Retourne le champ numérique du noeud."""
+    return noeud[0][1]
+
+
+def construit_arbre_huffman_depuis_liste(liste_car_nbre):
+    """À partir de la liste composée de listes du type [(c,n), None, None],
+    construit et retourne l'arbre de Huffman suivant l'algorithme classique.
+    Le résultat (l'arbre) est une liste composée de listes du type :
+    [(c,n), a_1, a_2] avec :
+    + n un entier.
+    + c un caractère ; dans ce cas a_1 et a_2 sont None et c'est une feuille
+        ou c est None ; Dans ce cas c'est un noeud interne et a_1 et a_2 sont
+        des sous-arbres. Par convention, a_1 est le sous-arbre gauche codant 0
+        et a_1 le sous-arbre droit codant 1."""
+    while len(liste_car_nbre) > 1:
+        liste_car_nbre = sorted(liste_car_nbre, key=lambda x: x[0][1])
+        noeud_gauche = liste_car_nbre.pop(0)
+        noeud_droit = liste_car_nbre.pop(0)
+        liste_car_nbre.append([(None, nb_caractères(
+            noeud_gauche) + nb_caractères(noeud_droit)), noeud_gauche, noeud_droit])
+
+    return liste_car_nbre[0]
+
+
+def construit_table_codage_depuis_arbre_huffman(arbre):
+    """Construit la table de codage à partir de l'arbre de Huffman.
+    Le resultat est un dictionnaire dont les clés sont les caractères et les
+    valeurs sont les codes binaires correspondant issus de l'arbre. Un code
+    binaire est retourné ici sous forme de chaine de cararctères de '0' et '1'.
+    """
+    codes = {}
+
+    def parcours(arbre, code):
+        if est_feuille(arbre):
+            codes[caractère(arbre)] = code
+        else:
+            parcours(arbre_gauche(arbre), code + "0")
+            parcours(arbre_droit(arbre), code + "1")
+
+    parcours(arbre, "")
+    return codes
+
+
+def code_fichier(fichier, table_codage):
+    """Code chaque caractère du fichier avec la table de codage dont les clés
+    sont les caractères et les valeurs les codes binaires sous forme de chaines
+    de '0' et de '1'.
+    Le résultat est une chaine de caractères de '0' et de '1'."""
+    # On utilisera construit_liste_ss_arbres_caracteres_nombre pour construire la table de codage
+    liste_feuilles = construit_liste_ss_arbres_caracteres_nombres(
+        fichier, False)
+
+    # On construit l'arbre de Huffman
+    arbre = construit_arbre_huffman_depuis_liste(liste_feuilles)
+
+    # On construit la table de codage
+    table = construit_table_codage_depuis_arbre_huffman(arbre)
+
+    result = ""
+
+    for char in open(fichier, "r").read():
+
+        if char in table:
+            result += table[char]
+
+    return result
+
+
+def decode_message(message_binaire, arbre):
+    """Prend en entrée une chaine de caractères de '0' et de '1' (message codé)
+    + un arbre de huffman. Retourne le décodage sous forme d'une chaine de
+    caractères."""
+    result = ""
+    node = arbre
+
+    for char in message_binaire:
+
+        if char == "0":
+            node = arbre_gauche(node)
+        else:
+            node = arbre_droit(node)
+
+        if est_feuille(node):
+            result += caractère(node)
+            node = arbre
+
+    return result
+
+
+# ----- Manipulations de ces fonctions.
+
+# Partie codage du fichier :
+fichier = "houghman.py"
+# fichier = "Codage-Huffman-Simple.py" # Pour coder le fichier source lui-même.
+liste_feuilles = construit_liste_ss_arbres_caracteres_nombres(fichier, False)
+arbre = construit_arbre_huffman_depuis_liste(liste_feuilles)
+table = construit_table_codage_depuis_arbre_huffman(arbre)
+# Codage Huffman en bin. du fichier
+message_codé = code_fichier(fichier, table)
+
+print(f"Le message codé est :\n{message_codé}")
+print(10*"---")
+print(f"La taille du message codé est de : {len(message_codé)} bits, soit " +
+      f"{len(message_codé)/8} octets.")
+print(10*"---")
+
+# Partie décodage :
+
+message_décodé = decode_message(message_codé, arbre)
+print(f"Le message décodé est : \n{message_décodé}")
diff --git a/Modeliser Resolution/in.txt b/Modeliser Resolution/in.txt
new file mode 100755
index 0000000..230d7d4
--- /dev/null
+++ b/Modeliser Resolution/in.txt	
@@ -0,0 +1,6 @@
+Voici quelques caractères à coder :
+
+ab€d €bbc
+cc
+
+4! = 24
-- 
GitLab