from random import randrange

plateau_image =[[0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0],
                [0, 0, 1, 0, 0, 0, 0],
                [0, 0, 2, 1, 2, 0, 0],
                [0, 1, 2, 2, 1, 0, 0],
                [2, 1, 1, 1, 2, 2, 0]]


plateau_rempl =[[0, 0, 1, 0, 0, 0, 0],
                [0, 0, 2, 1, 0, 0, 0],
                [0, 0, 1, 2, 0, 0, 0],
                [0, 1, 2, 1, 2, 0, 0],
                [2, 1, 2, 2, 1, 0, 0],
                [2, 1, 1, 1, 2, 2, 0]]


## Question 0

def afficher_plateau(plateau) :
    for i in range(len(plateau)) :
        print("|",end = "")
        for j in range (len(plateau[i])) :
            if plateau[i][j] == 1 :
                print(" ● |",end="")
            elif plateau[i][j] == 2 :
                print(" ◎ |",end="")
            else :
                print("   |",end="")
        print()
        print("■",end="")
        for j in range (len(plateau[i])) :
            print("   ■",end="")
        print()
    print(" ",end="")
    for j in range(len(plateau[0])) :
        print(" "+str(j) + "  ",end="")
    print()
    return


def gagnant_ligne(plateau,joueur) :
    for i in range(len(plateau)) :
        col = 0
        while col < len(plateau[i]) :
            if plateau[i][col] == joueur :
                continu = 0
                while col < len(plateau[i]) and plateau[i][col] == joueur :
                    col += 1
                    continu += 1
                    if continu == 4 :
                        return True
            else :
                col += 1
    return False

def gagnant_colonne(plateau,joueur) :
    for col in range(len(plateau[0])) :
        i = 0
        while i < len(plateau) :
            if plateau[i][col] == joueur :
                continu = 0
                while i < len(plateau) and plateau[i][col] == joueur :
                    i += 1
                    continu += 1
                    if continu == 4 :
                        return True
            else :
                i += 1
    return False



def gagnant_diag(plateau,joueur) :
    for i in range(len(plateau)) :
        for col in range (len(plateau[i])) :

            # Vérif diag droite
            ic,colc = i,col
            if plateau[i][col] == joueur :
                ic += 1
                colc += 1
                continu = 1
                while ic < len(plateau) and colc < len(plateau[ic]) and plateau[ic][colc] == joueur:
                    ic +=1
                    colc += 1
                    continu += 1
                    if continu == 4 :
                        return True

                # Vérif diag gauche
                ic,colc = i,col
                ic += 1
                colc -= 1
                continu = 1
                while ic < len(plateau) and colc >= 0 and plateau[ic][colc] == joueur :
                    ic +=1
                    colc -= 1
                    continu += 1
                    if continu == 4 :
                        return True
    return False


def verif_gagnant(plateau,joueur) :
    if gagnant_ligne(plateau,joueur) :
        return True
    if gagnant_colonne(plateau,joueur) :
        return True
    if gagnant_diag(plateau,joueur) :
        return True
    return False















## Question 2

def coup_possible(plateau : tuple) -> list :
    rep = []
    for j in range(len(plateau[0])) :
        if plateau[0][j] == 0 :
            rep.append(j)
    return rep
## Question 3

def jouer_coup(plateau,j,joueur) :

    for i in range (len(plateau)-1,-1,-1) :
        if plateau[i][j] == 0 :
            plateau[i][j] = joueur
            return


## Question 4

def annule_coup(plateau,j) :
    for i in range (0,len(plateau)) :
        if plateau[i][j] != 0 :
            plateau[i][j] = 0
            return








## Question 7
from random import randrange

def strategie(plateau,joueur) :
    possibilite = coup_possible(plateau)
    j = randrange(0,len(possibilite))
    return possibilite[j]















## Question 8
def comparer(strat1,strat2) :
    plateau = [[0 for j in range (7)] for i in range (6)]
    joueur = 1
    while len(coup_possible(plateau)) != 0 :
        if joueur == 1 :
            j = strat1(plateau,1)
            jouer_coup(plateau,j,1)
            gagnant = verif_gagnant(plateau,1)
            joueur = 2
            if gagnant :
                afficher_plateau(plateau)
                print("\nLe joueur 1 a gagné la partie")
                return 1
        else :
            j = strat2(plateau,2)
            jouer_coup(plateau,j,2)
            gagnant = verif_gagnant(plateau,2)
            joueur = 1
            if gagnant :
                afficher_plateau(plateau)
                print("\nLe joueur 2 a gagné la partie")
                return 2
    afficher_plateau(plateau)
    print("\nIl y a match nul.")
    return 0


p = ((3,4,5,7,5,4,3),(4,6,8,10,8,6,4),(5,8,11,13,11,8,5),(5,8,11,13,11,8,5),(4,6,8,10,8,6,4),(3,4,5,7,5,4,3))


## Question 9

def heuristique(plateau) :
    somme = 0
    for i in range (len(plateau)) :
        for j in range (len(plateau[i])) :
            if plateau[i][j] == 1 :
                somme += p[i][j]
            elif plateau[i][j] == 2 :
                somme -= p[i][j]
    return somme

























## Question 10

dic = {}
def score_min_max(plateau,h,prof,joueur) :
    tup = tuple([tuple(plateau[i]) for i in range(len(plateau))])
    if (tup,h,prof,joueur) in dic :
        return dic[tup,h,prof,joueur]
    if verif_gagnant(plateau,1) :
        dic[tup,h,prof,joueur] = 100000
        return 100000
    if verif_gagnant(plateau,2) :
        dic[tup,h,prof,joueur] = -100000
        return -100000
    if len(coup_possible(plateau)) == 0 :
        dic[tup,h,prof,joueur] = 0
        return 0
    if prof == 0 :
        dic[tup,h,prof,joueur] = h(plateau)
        return h(plateau)

    if joueur == 1 :
        max = -100000
        for j in coup_possible(plateau) :
            jouer_coup(plateau,j,joueur)
            v = score_min_max(plateau,h,prof-1,2)
            annule_coup(plateau,j)
            if v > max :
                max = v
        dic[tup,h,prof,joueur] = max
        return max
    else :
        min = 100000
        for j in coup_possible(plateau) :
            jouer_coup(plateau,j,joueur)
            v = score_min_max(plateau,h,prof-1,1)
            annule_coup(plateau,j)
            if v < min :
                min = v
        dic[tup,h,prof,joueur] = min
        return min


def coup_min_max(plateau,h,prof,joueur) :
    if joueur == 1 :
        max = -100000
        cp = coup_possible(plateau)
        jmax = cp[0]
        for j in cp :
            jouer_coup(plateau,j,joueur)
            v = score_min_max(plateau,h,prof-1,2)
            annule_coup(plateau,j)
            if v > max :
                max = v
                jmax = j
        return jmax
    else :
        min = 100000
        cp = coup_possible(plateau)
        jmin = cp[0]
        for j in coup_possible(plateau) :
            jouer_coup(plateau,j,joueur)
            v = score_min_max(plateau,h,prof-1,1)
            annule_coup(plateau,j )
            if v < min :
                min = v
                jmin = j
        return jmin
## Question 12

def strat(plateau,joueur) :
    return coup_min_max(plateau,heuristique,2,joueur)



## Question 13

lscore = [0,1,3,10,1000]

def heur_ligne(plateau) :
    somme = 0
    for i in range(len(plateau)) :
        for j in range (len(plateau[i])-4) :
            val = 0
            score = 0
            for jplus in range(4) :
                if val == 0 and plateau[i][j + jplus] !=0 :
                    val = plateau[i][j + jplus]
                    score += 1
                elif val !=  plateau[i][j + jplus] and val != 0 :
                    val = 3
                elif val != 0 and val == plateau[i][j + jplus] :
                    score += 1
            if val == 1 :
                somme += lscore[score]
            if val == 2 :
                somme -= lscore[score]

    return somme

def heur_colonne(plateau) :
    somme = 0
    for j in range(len(plateau[0])) :
        for i in range (len(plateau)-4) :
            val = 0
            score = 0
            for iplus in range(4) :
                if val == 0 and plateau[i][j] :
                    val = plateau[i + iplus][j]
                    score += 1
                elif val !=  plateau[i + iplus][j] and val != 0 :
                    val = 3
                elif val != 0 and val == plateau[i + iplus][j] :
                    score += 1
            if val == 1 :
                somme += lscore[score]
            if val == 2 :
                somme -= lscore[score]
    return somme


def heur_diag_droi(plateau) :
    somme = 0
    for i in range(len(plateau)-4) :
        for col in range (len(plateau[i])-4) :
            val = 0
            score = 0

            for plus in range (4) :
                if val == 0 and plateau[i + plus][col + plus] :
                    val = plateau[i + plus][col + plus]
                    score += 1
                elif val !=  plateau[i + plus][col + plus] and val != 0 :
                    val = 3
                elif val != 0 and val == plateau[i + plus][col + plus] :
                    score += 1
            if val == 1 :
                somme += lscore[score]
            if val == 2 :
                somme -= lscore[score]
    return somme

def heur_diag_gau(plateau) :
    somme = 0
    for i in range(len(plateau)-4) :
        for col in range (3,len(plateau[i])) :
            val = 0
            score = 0

            for plus in range (4) :
                if val == 0 and plateau[i + plus][col - plus] != 0 :
                    val = plateau[i + plus][col - plus]
                    score += 1
                elif val !=  plateau[i + plus][col - plus] and val != 0 :
                    val = 3
                elif val != 0 and val == plateau[i + plus][col - plus] :
                    score += 1
            if val == 1 :
                somme += lscore[score]
            if val == 2 :
                somme -= lscore[score]
    return somme




def heuristique2(plateau) :
    g = heur_colonne(plateau) + heur_ligne(plateau) + heur_diag_droi(plateau) + heur_diag_gau(plateau)
    return heur_colonne(plateau) + heur_ligne(plateau) + heur_diag_droi(plateau) + heur_diag_gau(plateau)

def strat2(plateau,joueur) :
    return coup_min_max(plateau,heuristique2,4,joueur)
