import matplotlib.pyplot as plt
from random import randint
from time import time


### Images de "tests" ####################################################################################

t1 = [
    [0, 0, 0, 1, 0],
    [0, 0, 0, 0, 1],
    [1, 0, 0, 0, 0],
    [0, 0, 1, 1, 0],
    [0, 1, 0, 0, 1],
]

t2 = [
    [0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
    [0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
    [0, 0, 0, 1, 1, 1, 1, 1, 1, 0],
    [0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
    [1, 1, 1, 1, 0, 0, 0, 0, 1, 0],
    [0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
    [0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
    [0, 0, 0, 1, 0, 1, 1, 1, 1, 1],
    [0, 0, 0, 1, 0, 0, 1, 0, 1, 0],
    [0, 0, 0, 1, 0, 0, 1, 0, 1, 0],
]

##########################################################################################################


def aff(t):
    plt.imshow(t, cmap="binary")
    # plt.xticks( [i for i in range(len(t[0]))] )
    # plt.yticks( [i for i in range(len(t))] )
    plt.show()


def marque_carre(t, lig, col, taille):
    for y in range(taille):
        for x in range(taille):
            t[lig - y][col - x] = 0.25
    t[lig][col] = 0.30


def genere_tab_alea(n, ratio_noir):
    t = []
    for lig in range(n):
        t.append([])
        for col in range(n):
            alea = randint(0, 100)
            (t[lig]).append(1 if alea <= ratio_noir else 0)
    return t


def PlusGrandCarreBlanc_Rec(t, lig, col):
    global compteur_naif
    compteur_naif += 1
    if t[lig][col] == 1:
        return 0
    elif (lig == 0) or (col == 0):
        return 1
    else:
        # Petit truc pour éviter de calculer toutes les valeurs dans le min si une des trois est déjà à 0 (au min)
        h = PlusGrandCarreBlanc_Rec(t, lig - 1, col)
        if h == 0:
            return 1
        g = PlusGrandCarreBlanc_Rec(t, lig, col - 1)
        if g == 0:
            return 1
        gh = PlusGrandCarreBlanc_Rec(t, lig - 1, col - 1)
        if gh == 0:
            return 1
        return min(g, h, gh) + 1
    # return min(PlusGrandCarreBlanc_Rec(t, lig - 1, col), PlusGrandCarreBlanc_Rec(t, lig - 1, col - 1), PlusGrandCarreBlanc_Rec(t, lig, col - 1)) + 1


def PlusGrandCarreBlanc_memo(t, lig, col):
    global compteur_memo
    compteur_memo += 1
    if t_memo[lig][col] != -1:
        return t_memo[lig][col]
    if t[lig][col] == 1:
        t_memo[lig][col] = 0
        return 0
    elif (lig == 0) or (col == 0):
        t_memo[lig][col] = 1
        return 1
    else:
        res = (
            min(
                PlusGrandCarreBlanc_memo(t, lig - 1, col),
                PlusGrandCarreBlanc_memo(t, lig, col - 1),
                PlusGrandCarreBlanc_memo(t, lig - 1, col - 1),
            )
            + 1
        )
        t_memo[lig][col] = res
        return res


def RechercheCarreBlanc_naif(t):
    l, c = 0, 0
    tmax = 0
    nb_lig, nb_col = len(t), len(t[0])
    for lig in range(nb_lig):  # On parcourt les lignes
        for col in range(nb_col):  # on parcourt les colonnes
            taille = PlusGrandCarreBlanc_Rec(
                t, lig, col
            )  # (le tableau est carré donc toutes les lignes ont la même longueur)
            if taille >= tmax:  # Si taille est > à tmax
                l, c = lig, col  # on a lig,col qui sont les coordonnées voulues
                tmax = taille  # on met à jour le tmax
    return l, c, tmax


def RechercheCarreBlanc_memo(t):
    l, c, tmax = 0, 0, 0
    nb_lig, nb_col = len(t), len(t[0])
    for lig in range(nb_lig):
        for col in range(nb_col):
            taille = PlusGrandCarreBlanc_memo(
                t, lig, col
            )  # On utilise PlusGrandCarreBlanc_memo()
            if taille >= tmax:
                l, c = lig, col
                tmax = taille
    return l, c, tmax


def PlusGrandCarreBlanc_BU(t):
    nb_lig, nb_col = len(t), len(t[0])
    res = [[-1 for _ in range(nb_col)] for _ in range(nb_lig)]
    for lig in range(nb_lig):
        for col in range(nb_col):
            if t[lig][col] == 1:  # sous-problème de taille "0"
                res[lig][col] = 0
            elif lig == 0 or col == 0:  # sous-problème de taille "1"
                res[lig][col] = 1
            else:
                res[lig][col] = 1 + min(
                    res[lig - 1][col], res[lig][col - 1], res[lig - 1][col - 1]
                )
    return res


def RechercheCarreBlanc_BU(t):
    l, c, tmax = 0, 0, 0
    nb_lig, nb_col = len(t), len(t[0])
    res = PlusGrandCarreBlanc_BU(t)  # Avec l'algorithme BOTTOM UP
    for lig in range(nb_lig):
        for col in range(nb_col):
            taille = res[lig][
                col
            ]  # On utilise le tableau fournit par PlusGrandCarreBlanc_BU()
            if taille >= tmax:
                l, c = lig, col
                tmax = taille
    return l, c, tmax


#############################################
# Programme principal
#############################################

compteur_naif = 0
compteur_memo = 0
n = 40
ratio = 50

t_memo = [[-1 for i in range(n)] for j in range(n)]
t3 = genere_tab_alea(n, ratio)

s = time()
res = RechercheCarreBlanc_naif(t3)
e = time()
print("Durée de l'algo naif : ", e - s, "nombre d'appels récursifs : ", compteur_naif)

s = time()
res = RechercheCarreBlanc_memo(t3)
e = time()
print(
    "Durée de l'algo avec memoïsation : ",
    e - s,
    "nombre d'appels récursifs : ",
    compteur_memo,
)

s = time()
res = RechercheCarreBlanc_BU(t3)
e = time()
print("Durée de l'algo avec BOTTOM UP : ", e - s)

marque_carre(t3, res[0], res[1], res[2])
aff(t3)
