#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Quelle est la probabilité de gagner au Yahtzee ? 

On joue avec des dés pythoniens : ils portent les valeurs 0, 1, 2, 3, 4, 5. 
"""

nb_faces = 6 # s'il nous venait l'idée saugrenue de changer de dés... 
nb_des   = 5
nb_tentatives = 3 

from random import randrange

def lancer(nb_des_lances):
    L = []
    for i in range(nb_des_lances):
        L.append(randrange(nb_faces))
    return L

def yathzee(L):
    """
    On réussit un yathzee lorsque tous les dés indiquent la même valeur. 
    """
    reussi = True
    for de in L[2:]:
        reussi = reussi and (de==L[0])
    return reussi

def stats(L):
    """
    On compte le nombre d'occurences pour chaque valeur. 
    """
    S = [0]*nb_faces
    for de in L:
        S[de] += 1
    return S

def chercher_max(S):
    """
    La liste S contient le nombre d'occurences de chaque valeur. 
    On en déduit la valeur qui est apparue le plus grand nombre de fois. 
    idx_m = valeur apparue le plus grand nombre de fois
    m     = nombre d'occurences de idx_m
    """
    m, idx_m = S[0], 0
    for (i, v) in enumerate(S):
        if v>=m:
            m, idx_m = v, i
    return idx_m, m

def racine(L):
    """
    On conserve les dés du lancer L qui sont les plus nombreux 
    à porter la même valeur. 
    Si deux valeurs apparaissent deux fois ou si les cinq 
    valeurs sont distinctes, on conserve la plus grande valeur. 
    On renvoie la liste des dés conservés pour le tirage suivant. 
    """
    S = stats(L)
    valeur, repetitions = chercher_max(S)
    return [valeur]*repetitions

def partie():
    R = [] # dés conservés avant le prochain lancer
    for essai in range(nb_tentatives):
        # nombre de dés à lancer
        nb_des_lances = nb_des - len(R)
        # nouveau tirage
        L = R + lancer(nb_des_lances)
        # print(L)
        if yathzee(L):
            return True
        # on conserve les valeurs les plus nombreuses
        R = racine(L)
    # si on sort de la boucle, c'est qu'on n'a pas réussi à faire yahtzee
    return False

def estimation_proba(N):
    """
    On réalise N expériences aléatoires dans les mêmes conditions et 
    on compte la proportion de succès. 
    """
    nb_succes = 0
    for i in range(N):
        nb_succes += partie()
    return nb_succes/N

def intervalle(N, seuil):
    """
    L'inégalité de Bienaymé-Tchebychev va nous servir à estimer la 
    probabilité de réussir un yahtzee. 
   
    Autrement dit, on calcule la moyenne empirique de N v.a. de Bernoulli 
    indépendantes et de même paramètre p. On sait que la distance entre 
    cette moyenne empirique et la probabilité cherchée p est supérieure 
    au seuil alpha avec une probabilité inférieure à p*q/(N*alpha**2). 
    """
    moy_empirique = estimation_proba(N)
    risque = moy_empirique/(N*seuil**2)   
    a, b = moy_empirique - seuil, moy_empirique + seuil
    message = "{:6.4%} ≤ p ≤ {:6.4%} avec un risque de {:4.2%}".format(a, b, risque)
    print(message)
    
"""
Application numérique : 
intervalle(1000000, 0.001) → 4.8007% ≤ p ≤ 5.0007% avec un risque de 4.90%. 
(calcul un peu long !)
"""