from math import log
from collections import Counter
import sys
s1 = "CODAGEINFORMATIONETCALCUL"
s2 = "TOBEORNOTTOBEORTOBEORNOT"
# print(len(s1) * 8)
# print(len(s2) * 8)
# sys.exit()
def entropy(p):
    return -sum(pi * log(pi, 2) for pi in p)
"""print(entropy([0.5, 0.5]))
print(entropy([0.4, 0.6]))
print(entropy([0.01, 0.99]))
print(entropy([0.99, 0.01]))"""
# sys.exit()
def string_entropy(s):
    n = len(s)
    c = Counter(s)
    p = []
    for nb_occ in c.values():
        p.append(nb_occ / n)
    return entropy(p)
# print(Counter("coucou"))
# print(string_entropy(s1), 'bits pour', s1)
# print(string_entropy(s2), 'bits pour', s2)
# sys.exit()
img1 = ["11111111",
        "11111111",
        "00000000",
        "00000000",
        "11111111",
        "11111111",
        "00000000",
        "00000000"]
# sys.exit()
img2 = [("1" * 4 + "0" * 4) * 8]
# Comment couper une liste
l = list(range(20))
print(l)
print(l[5:15:2])
#print(l[a:b:-1])
print(l[:-1])
print(l[::-1])  # Inverser
# sys.exit()
img3 = ["10" * 4, "01" * 4, "0" * 16, "1" * 16, "0" * 16]
print(bin(1)[2:].zfill(3))
# sys.exit()
def binary(n):
    return bin(n - 1)[2:].zfill(3)  # Rempli avec des 0 à gauche
def rle(img):
    seq = ''.join(img)
    n = len(seq)
    current = ''
    nb_occ = 0
    encoding = ""
    for i in range(n):
        if seq[i] != current or nb_occ == 8:
            if current:
                # print(current, nb_occ)
                encoding += current + binary(nb_occ)
            current = seq[i]
            nb_occ = 1
        else:
            nb_occ += 1
    encoding += current + binary(nb_occ)
    return encoding
print(rle(img1), len(rle(img1)))
print(rle(img2), len(rle(img2)))
print(rle(img3), len(rle(img3)))
# sys.exit()
new_img3 = ["2" * 4 + "1" * 4 + "0" * 8 + "3" * 8 + "0" * 8]
# print(rle(new_img3), len(rle(new_img3)))
N = 1000000
freq = [0.45, 0.13, 0.12, 0.16, 0.09, 0.05]
length = [1, 3, 3, 3, 4, 4]
# print(sum(freq[i] * length[i] * N for i in range(6)) / (3 * N))
print('huffman', sum(freq[i] * length[i] for i in range(6)))
print('shannon', entropy(freq))
def lzw(s):
    dico = {}
    # Initialize
    for value in range(255):
        dico[chr(value)] = value
    new_value = 256
    acc = ""
    encoding = []
    for letter in s:
        acc += letter
        if acc not in dico:
            dico[acc] = new_value
            this_code = dico[acc[:-1]]
            new_value += 1
            encoding.append(this_code)
            acc = acc[-1]
    this_code = dico[acc]
    for letter, v in dico.items():
        if v > 255:
            print(letter, v)
    encoding.append(this_code)
    return encoding
encoding = lzw("TOBEORNOTTOBEORTOBEORNOT")
print(encoding)
print(''.join(list(map(chr, encoding))))
# sys.exit()
def decode_lzw(encoding):
    dico = {}
    # Initialize
    for value in range(255):
        dico[value] = chr(value)
    new_value = 256
    plain = ""
    last_output = ""
    for code in encoding:
        if code in dico:
            output = dico[code]
            plain += output
            if last_output:
                dico[new_value] = last_output + output[0]
                new_value += 1
        last_output = output
    return plain
print(decode_lzw([84, 79, 66, 69, 79, 82, 78, 79, 84, 256, 258, 260, 265, 259, 261, 263]))