# dilemme du prisonnier itéré
# version tournoi

from random import choice, randint, seed

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'


# Coyote
# Compte le nombre de trahisons et punit de plus en plus fort

etat_coyote = 0
# coyote peut être dans trois états: 0 (zen), 1 (punition), 2 (acceptation).
nb_trahisons = 0
duree_punition = 1
duree_paix = 2
def coyote(liste_lui,liste_moi):
    global etat_coyote, nb_trahisons, duree_punition, duree_paix
    if len(liste_lui)>2:
        if liste_lui[-1]=='T' and etat_coyote==0:
            etat_coyote = 1
            nb_trahisons += 1
            duree_punition = 3*nb_trahisons
        if etat_coyote == 1:
            duree_punition -= 1
            if duree_punition==0:
                etat_coyote = 2
            return 'T'
        if etat_coyote == 2:
            if duree_paix>0:
                duree_paix -= 1
            else:
                etat_coyote = 0
                duree_paix = 2
            return 'C'
        return 'C'
    else:  # 3 premiers coups
        return 'C'


# Louis
# coopère seulement si l'autre a coopéré en majorité sur les trois derniers coups
# se méfie de Toujours seul

def louis(liste_lui,liste_moi):
    if len(liste_lui)>0:
        lyste = []
        lyste.append(liste_lui[-1])

        if len(liste_lui)>1:
            lyste.append(liste_lui[-2])

        if len(liste_lui)>2:
            lyste.append(liste_lui[-3])

        if lyste.count('C') > lyste.count('T'):
            return 'C'
        else :
            return 'T'
        
    else :
        return 'C'


#Patrick
    
def patrick(liste_lui,liste_moi):
    global choix
    if len (liste_lui)>0:
        if len (liste_lui)>1:
            if liste_lui[-1]=="C" and liste_lui[-2]=="C":
                return "T"
            elif liste_lui [-1]=="C":
                return choice(choix)
            else:
                return "T"
        elif liste_lui[-1]=="C":
            return choice(choix)
        else:
            return "T"
    else:
        return "T"


# Olivier
def olivier(liste_lui, liste_moi):
    if len(liste_lui)>1:
        if len(liste_lui)%2==0:
            return 'T'
        else:
            return 'C'
    else:
        return 'C'


# Strategie de Normand

# UTILISE LA FONCTION randint() !!

# joue trois fois t puis trois fois c
# joue differemment si il voit que l'adversaire à tendance à jouer bcp t ou bcp c
# les trois premiers coups sont fait au hasard

def normand(liste_lui, liste_moi):
    if len(liste_lui)>0:
        if liste_lui.count('C') > 2*len(liste_lui)//3 and len(liste_lui)> 5:
            return 'T'
        elif liste_lui.count('T') > 2*len(liste_lui)//3 and len(liste_lui)> 5:
            return 'T'
        elif len(liste_lui)>=3:
            if liste_moi[-3] == 'T':
                return 'C'
            else:
                return 'T'  
        else: #pour les trois premiers coups
                choix = randint(1, 2)
                if choix == 1:
                    return 'C'
                else:
                    return 'T'
    else:
        return 'C'


def benjamin(liste_lui,liste_moi):
    global choix
    if len(liste_lui)>1:       # 3 au 15e coups
        if len(liste_lui)>14:   # tous les autres coups, minorité
            if liste_lui.count('C') > len(liste_lui)//2:
                return 'T'
            else:
                return 'C'
        return liste_lui[-2]    
    else:                   # premier et deuxième coups
        return choice(choix)


#Stratégie de Stève Chételat

def steve(liste_lui,liste_moi):
    i=randint(1,100)
    if i<45:
        return 'T'
    else:
        if liste_lui.count('C') < len(liste_lui)//2:
            return 'C'
        else:
            return 'T'


def colin(liste_lui,liste_moi):
    i=randint(1,100)
    if i<=35:
        return 'T'
    if i>35:
        if liste_lui.count('C')< liste_lui.count('T'):
            return 'C'
        elif liste_lui.count('C')==liste_lui.count('T'):
            return 'T'
        else:
            return 'T'


def nicolas(liste_toi, liste_moi):
    global choix
    
    tour = len(liste_moi)
    coups = ['T','C','T','C']
    if tour == 0:
        return 'C' #coups[tour] #choice(choix)
    elif tour < 4:
        return choice(choix) #C coups[tour]
    else:
        if 'T' not in liste_toi:
            return 'T'
        elif 'C' not in liste_toi:
            return 'T'
        liste_str_t =str(liste_toi)[len(str(liste_toi))-16:len(str(liste_toi))-1]
        if len(str(liste_moi)) <= 32:
            liste_str_m = str(liste_moi)[1:len(str(liste_moi))-1]
        else:
            liste_str_m = str(liste_moi)[len(str(liste_moi))-32:len(str(liste_moi))-1]
        if liste_str_t in liste_str_m:
            return 'C'
        else:
            if liste_toi.count('C') > len(liste_toi)//2:
                return 'C'
            else:
                return 'T'


# Le tournoi 2012

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['Patrick'] = []
liste['Louis'] = []
liste['Benjamin'] = []
liste['Steve'] = []
liste['Colin'] = []
liste['Nicolas'] = []
liste['Olivier'] = []
liste['Normand'] = []

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['Louis'] = lambda lui, moi : louis(lui,moi)
strategie['Patrick'] = lambda lui, moi : patrick(lui,moi)
strategie['Benjamin'] = lambda lui, moi : benjamin(lui,moi)
strategie['Steve'] = lambda lui, moi : steve(lui,moi)
strategie['Colin'] = lambda lui, moi : colin(lui,moi)
strategie['Nicolas'] = lambda lui, moi : nicolas(lui,moi)
strategie['Normand'] = lambda lui, moi : normand(lui,moi)
strategie['Olivier'] = lambda lui, moi : olivier(lui,moi)


nb_total_coups = 534  # à modifier

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(45226)
            etat_coyote = 0
            # coyote peut être dans trois états: 0 (zen), 1 (punition), 2 (acceptation).
            nb_trahisons = 0
            duree_punition = 1
            duree_paix = 2
            while nb_coups < nb_total_coups :
                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")

