# dilemme du prisonnier itéré
# version tournoi

from random import *

choix = ['T','C']  # T : trahit, C : coopère

def gain(lui,moi):
    if lui=='C' and moi=='C':
        return 3
    elif lui=='C' and moi=='T':
        return 5
    elif lui=='T' and moi=='C':
        return 0
    elif lui=='T' and moi=='T':
        return 1


# Toujours seul
# ne coopère jamais

def toujours_seul(liste_lui,liste_moi):
    return 'T'


# Bonne poire
# coopère toujours

def bonne_poire(liste_lui,liste_moi):
    return 'C'


# Aléatoire
# joue avec une probabilité égale 'T' ou 'C'

def aleatoire(liste_lui,liste_moi):
    global choix
    return choice(choix)


# Donnant donnant
# coopère seulement si l'autre joueur a coopéré au coup précédent.

def donnant_donnant(liste_lui,liste_moi):
    if len(liste_lui)>0:
        return liste_lui[-1]
    else:  # premier coup
        return 'C'


# Majorité
# coopère seulement si l'autre joueur a coopéré en majorité.

def majorite(liste_lui,liste_moi):
    if len(liste_lui)>0:
        if liste_lui.count('C') > len(liste_lui)//2:
            return 'C'
        else:
            return 'T'
    else:  # premier coup
        return 'C'


# Ajouter les stratégies des joueurs ici

# Coyote
# Commence par coopérer. Coopère tant que l'autre n'a pas trahi 2 fois.

def coyote(liste_lui,liste_moi):
    if len(liste_lui)==0:
        return 'C'
    if liste_lui.count('T') >= 2:
        return 'T'
    else:
        return 'C'


# Loïc
# trahit à chaque fois.

def loic(liste_lui,liste_moi):
    return 'T'


# Timothy
def timothy(liste_lui,liste_moi):
    prime_numbers=[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
    combinations=[(7,5)]
    if len(liste_lui)>0:
        if len(liste_lui)//7==0:
            if liste_lui.count('C') > len(liste_lui)//2:
                return 'C'
            else:
                return 'T'
        elif len(liste_lui)//2==0:
            global choix
            return choice(choix)
        else:
            return liste_lui[-1]
    else:  # premier coup
        return 'C'


# Levin
# je trahis tout le temps inchallah ça passe

def levin(liste_lui,liste_moi):
    return 'T'


# Aaron
# Donnant donnant en commançant par 'C' mais qui joue 'T' au 2eme coup.

def aaron(liste_lui,liste_moi):
    if len(liste_lui) == 1:
        return 'T'
    elif len(liste_lui)>0:
        return liste_lui[-1]
    else: # premier coup
        return 'C'


# Olti
# Se base sur la probabilité qu'a l'autre de jouer C ou T
def olti(liste_lui,liste_moi) :
    if liste_lui.count('T') > liste_lui.count('C') :
        return 'T'
    elif liste_lui.count('C') > liste_lui.count('T') :
        return 'C'
    elif  liste_lui.count('T') == liste_lui.count('C') :
        return choice(choix)


# Fallou
def fallou(lm, ll):

    class Fonctions:

        def toujours_seul():
            return 'T'

        def bonne_poire():
            return 'C'

        def aleatoire():
            global choix
            return choice(choix)

        def donnant_donnant(liste_lui,liste_moi):
            if len(liste_lui)>0:
                return liste_lui[-1]
            else:
                return 'C'

        def majorite(liste_lui,liste_moi):
            if len(liste_lui)>0:
                if liste_lui.count('C') > len(liste_lui)//2:
                    return 'C'
                else:
                    return 'T'
            else:
                return 'C'

    if len(ll) == 0:
        return choice((Fonctions.bonne_poire(), Fonctions.toujours_seul(), Fonctions.aleatoire(), Fonctions.donnant_donnant(ll, lm), Fonctions.majorite(ll, lm)))

    else:
        if ll[-1] == "T":
            return Fonctions.toujours_seul()

        else:
            return choice((Fonctions.bonne_poire(), Fonctions.toujours_seul(), Fonctions.aleatoire(), Fonctions.donnant_donnant(ll, lm), Fonctions.majorite(ll, lm)))


# Hugo
def hugo(liste_lui, liste_moi):
    if len(liste_lui) > 0:
        if liste_lui.count('C') < liste_lui.count('T'):
            return 'C'
        else:
            return 'T'
    else:
        return 'T'


# Jonathan
def jonathan(liste_lui,liste_moi):
    if len(liste_lui)>1:
        x = liste_lui[-2]
        if x == 'T':
            return 'C'
        else:
            return 'T'
    else:  # premier coup
        return 'C'


# Serafin
def serafin(liste_lui,liste_moi):
    if nb_coups < 15:
        if len(liste_lui)>0:
            return liste_lui[-1]
        else:  # premier coup
            return 'C'
    else:
        return 'T'

# Arthur

# Défini pour pouvoir compter le nombre de lettres consécutives
def compter_lettres_consecutives(chaine, lettre):
    compteur = 0
    for T in chaine:
        if T == lettre:
            compteur += 1
        else:
            compteur = 0  # Réinitialiser le compteur si la lettre actuelle n'est pas celle recherchée

        if compteur >= 2:  # Modifier cette condition si vous voulez compter un nombre différent de lettres consécutives
            return 'T'
    return 'C'

# Joue tout le temps vrai, sauf quand l'autre trahi 2x de suite
def arthur(liste_lui, liste_moi):
    if len(liste_lui) > 0:
        resultat = compter_lettres_consecutives(liste_lui, 'T')
    else:  # premier coup
        resultat = 'C'
    return resultat


# Le tournoi

liste = {}
strategie = {}
score = {}
duel = {}

# ajouter des joueurs ci-dessous, selon les modèles des joueurs existants
# commencer ici
liste['Toujours seul'] = []
liste['Bonne poire'] = []
liste['Majorité'] = []
liste['Aléatoire'] = []
liste['Donnant donnant'] = []
liste['Coyote'] = []
liste['Loïc'] = []
liste['Timothy'] = []
liste['Levin'] = []
liste['Aaron'] = []
liste['Olti'] = []
liste['Fallou'] = []
liste['Hugo'] = []
liste['Jonathan'] = []
liste['Serafin'] = []
liste['Arthur'] = []

strategie['Toujours seul'] = lambda lui, moi : toujours_seul(lui,moi)
strategie['Bonne poire'] = lambda lui, moi : bonne_poire(lui,moi)
strategie['Majorité'] = lambda lui, moi : majorite(lui,moi)
strategie['Aléatoire'] = lambda lui, moi : aleatoire(lui,moi)
strategie['Donnant donnant'] = lambda lui, moi : donnant_donnant(lui,moi)
strategie['Coyote'] = lambda lui, moi : coyote(lui,moi)
strategie['Loïc'] = lambda lui, moi : loic(lui,moi)
strategie['Timothy'] = lambda lui, moi : timothy(lui,moi)
strategie['Levin'] = lambda lui, moi : levin(lui,moi)
strategie['Aaron'] = lambda lui, moi : aaron(lui,moi)
strategie['Olti'] = lambda lui, moi : olti(lui,moi)
strategie['Fallou'] = lambda lui, moi : fallou(lui,moi)
strategie['Hugo'] = lambda lui, moi : hugo(lui,moi)
strategie['Jonathan'] = lambda lui, moi : jonathan(lui,moi)
strategie['Serafin'] = lambda lui, moi : serafin(lui,moi)
strategie['Arthur'] = lambda lui, moi : arthur(lui,moi)

# terminer là


for joueur in liste.keys():
    score[joueur] = 0

for i in liste.keys():  # i et j sont les joueurs
    for j in liste.keys() :
        liste[i] = []   # on recommence une partie
        liste[j] = []
        if i>=j:
            nb_coups = 0
            score_joueur1 = 0
            score_joueur2 = 0
            seed(5478) # germe du générateur aléatoire
            while nb_coups < 654 :   # à modifier
                coup_joueur1 = strategie[i](liste[j],liste[i])
                coup_joueur2 = strategie[j](liste[i],liste[j])
                liste[i].append(coup_joueur1)
                if i!=j:
                    liste[j].append(coup_joueur2)
                score_joueur1 += gain(coup_joueur2,coup_joueur1)
                score_joueur2 += gain(coup_joueur1,coup_joueur2)
                nb_coups += 1
            duel[(i,j)] = score_joueur1
            if i!=j:
                duel[(j,i)] = score_joueur2
            score[i] += score_joueur1
            if i!=j:
                score[j] += score_joueur2

# affichage des résultats

def trie_par_valeur(d):
    #retourne une liste de tuples triée selon les valeurs
    return sorted(d.items(), key=lambda x: x[1])

def trie_par_cle(d):
    #retourne une liste de tuples triée selon les clés
    return sorted(d.items(), key=lambda x: x[0])

score_trie = trie_par_valeur(score)
score_trie.reverse()
for i in range(0,len(score_trie)):
    print(score_trie[i][0],":",score_trie[i][1])
print()
duel_trie = trie_par_cle(duel)
for i in range(0,len(duel_trie)):
    print(duel_trie[i][0][0],"contre",duel_trie[i][0][1],"gagne",duel_trie[i][1],"pts")

