# dilemme du prisonnier itéré
# version tournoi
# février 2018

from random import choice, randint, seed, random

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'

# Sebastián

def sebastian(liste_lui,liste_moi):
    nbr=randint(0,10)
    if nbr>6:
        return 'T'
    else :
        return 'C'

# Charlotte

def charlotte(liste_lui,liste_moi):
    if len(liste_lui)>2:
        if liste_lui[-1] == 'T' and liste_lui [-2] == 'T'  and liste_lui [-3]=='T':
            return 'T'
        elif liste_lui[-1] == 'T' and liste_lui[-2] =='C' and liste_lui[-3]=='T':
            return 'T'
        elif liste_lui[-1] == 'T' and liste_lui [-2] == 'T'  and liste_lui [-3]=='C':
            return 'T'
        elif liste_lui[-1] == 'C' and liste_lui [-2] == 'T'  and liste_lui [-3]=='C':
            return 'T'
        elif liste_lui[-1] == 'C' and liste_lui [-2] == 'C'  and liste_lui [-3]=='T':
            return 'T'
        elif liste_lui[-1] == 'C' and liste_lui [-2] == 'T'  and liste_lui [-3]=='C':
            return 'T'
        elif liste_lui[-1] == 'T' and liste_lui [-2] == 'C'  and liste_lui [-3]=='C':
            return 'T'
        else:
            return 'C'        
    elif len(liste)>1:
        return 'C'
    else:
        return 'C'

# Fabrice
# pas du tout aléatoire

a=6
e=0.4
def fabrice(uil,oim):                #codé avec amour.
    global a
    e=0.4
    d=0.9
    if len(uil)==a:
        b=uil.count('C')/a
        c=random()
        a+=1
        if b==1:
            return 'T'
        if b>d:
            if c<e:
                return 'T'
            else:
                return 'C'
        if c+0.15<b:
            return 'C'
        else:
            return 'T'
    else:
        return 'C'

#Stratégie Mattéo pour le tournoi
#Trahi jusqu'à ce que l'autre trahisse, coopère puis
#trahi à nouveau quand l'autre coopère

def matteo(liste_lui,liste_moi):
    if len(liste_lui)>0:
        if liste_lui[-1]=='C':
            return 'T'
        else:
            return 'C'
    else:
        return 'T'

# Lena
# joue le meme coup que l'autre joueur a fait trois coups avant.
def lena(liste_lui,liste_moi):
    if len(liste_lui)>2:
        return liste_lui[-3]
    else:
        return 'C'

# Gaëtan
# a une chance sur trois de trahir
def gaetan(liste_lui,liste_moi):
    liste = [1,2,3]
    x = choice(liste)
    if x == 1:
        return 'C'
    elif x == 2:
        return 'T'
    else:
        return 'C'

#Kiril

def kiril(liste_lui,liste_moi):
    
    if len(liste_lui)==0:
        return 'C'
    if liste_lui.count('T') >= 2:
        return 'T'
    else:
        return 'C'

# Yanick
# Coopérer les 10 premiers coups, puis coopérer si l'adversaire
# coopère les deux derniers coups qu'il a joué.
def yanick(liste_lui,liste_moi):
    if len(liste_lui)<10:
        return 'C'
    if liste_lui[-1]=='C' and liste_lui[0]=='C':
        return 'C'
    else:
        return'T'

#Shugirshan
#Trahi après avoir coopéré dix fois et commence la partie en trahissant

def shugirshan(liste_lui,liste_moi):
    if len(liste_lui)>10:
        return liste_lui[-10]
    elif len(liste_lui)//1:
        return 'C'
    else:  
        return 'T'

# Romain
# punit les trahisons

c=0
def romain (liste_lui, liste_moi):
    global k, c
    if len(liste_lui)>0 :
        while c == 0 :
            if liste_lui [-1]=='T':
                k=liste_lui.count('T')
                c=k
            else :
                return 'C'
        while c != 0 :
            c-=1
            return 'T'
    else :
        c=0
        return 'C'

# Orelian

pourcent = 0.55
def orelian(liste_lui,liste_moi):
    global pourcent
    
    if len(liste_lui) > 0:
        
        if liste_lui[-1] == liste_moi[-1]:
            return liste_moi[-1]
        
        if(liste_lui.count('T') <= len(liste_lui)*pourcent):
            return 'C'
        
        else:
            return 'T'
        
    else:
        return 'C'

#Nicolas
    
def nicolas(liste_lui,liste_moi):
    if len(liste_lui)<1:
        return "C"
    elif len(liste_lui)<2:
        if liste_lui[0]=="T":
            return "T"
        else:
            return "C"
    elif choice(range(30))<3:
        return "T"
    elif liste_lui[-1]=="C" and liste_lui[-2]=="C" and liste_moi[-2]=="T":
        return "T"
    elif liste_moi[-1] == "C" and liste_lui[-1]== "C":
        return "C"
    else:
        if liste_lui[-1]=="T" and liste_lui[-2]=="T":
            return "T"
        elif liste_lui[-1]=="T" and liste_lui[-2]=="C" and liste_moi[-1]=="C":
            return "C"
        else:
            return choice(choix)

        
# Le tournoi 2018

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['Sebastián'] = []
liste['Charlotte'] = []
liste['Fabrice'] = []
liste['Matteo'] = []
liste['Léna'] = []
liste['Gaëtan'] = []
liste['Kiril'] = []
liste['Yanick'] = []
liste['Shugirshan'] = []
liste['Romain'] = []
liste['Orélian'] = []
liste['Nicolas'] = []


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['Sebastián'] = lambda lui, moi : sebastian(lui,moi)
strategie['Charlotte'] = lambda lui, moi : charlotte(lui,moi)
strategie['Fabrice'] = lambda lui, moi : fabrice(lui,moi)
strategie['Matteo'] = lambda lui, moi : matteo(lui,moi)
strategie['Léna'] = lambda lui, moi : lena(lui,moi)
strategie['Gaëtan'] = lambda lui, moi : gaetan(lui,moi)
strategie['Kiril'] = lambda lui, moi : kiril(lui,moi)
strategie['Yanick'] = lambda lui, moi : yanick(lui,moi)
strategie['Shugirshan'] = lambda lui, moi : shugirshan(lui,moi)
strategie['Romain'] = lambda lui, moi : romain(lui,moi)
strategie['Orélian'] = lambda lui, moi : orelian(lui,moi)
strategie['Nicolas'] = lambda lui, moi : nicolas(lui,moi)




nb_total_coups = int(input("Nombre total de coups par duel (200-5000) ? "))
germe = int(input("Germe du générateur de nombres pseudo-aléatoires ? "))
print()

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(germe)
            etat_coyote = 0
            progamer=0
            # coyote peut être dans trois états: 0 (zen), 1 (punition), 2 (acceptation).
            nb_trahisons = 0
            duree_punition = 1
            duree_paix = 2
            c = 0
            a=6
            e=0.4
            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('{:2d}'.format(i+1),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")

