# -*- coding: utf-8 -*-

# Chapitre 4: Simulations probabilistes (cas discret)


#%% Fonctions définies précédemment
# On pourra réutiliser dans ce chapitre la fonction affiche_tableau donnée dans le chapitre2.
# On pourra aussi avoir besoin de la valeur de pi (accessible depuis le module math):

from math import pi


def affiche_tableau(tab):
    nblign,nbcol=len(tab),len(tab[0]) #nb de lignes et de colones
    largeur=[max(len(str(tab[i][j])) for i in range(nblign))
             for j in range(nbcol)] #la largeur maximale de chaque colonne
    for l in range(2*len(tab)+1): #afichage ligne par ligne:
        if l%2==0: # affichage d'une ligne horizontale
            if l==0: g,m,d="┌┬┐"
            elif l==2*len(tab): g,m,d="└┴┘"
            else: g,m,d="├┼┤"
            print(g+m.join(["─"*larg for larg in largeur])+d)
        else:
            print("│"+"│".join([case+" "*(largeur[col]-len(case))
                for col in range(nbcol) for case in [str(tab[l//2][col])]])+"│")


#%% I. Exemple du lancer de dés

# On lance deux dés à six faces, et on calcule la somme X des chiffres indiqués.


#%% 1. Calcul de probabilités


# On détermine tout d'abord la loi de X, c'est à dire que l'on calcule chacune des probabilités ℙ[X=0], ℙ[X=1], ℙ[X=2], ℙ[X=3], etc.
#
# Écrire une fonction proba_des telle que proba_des(k) renvoie ℙ[X=k]


def proba_des(k):




#%% 2. Simulation d'un lancer de dés

# Le module random contient une fonction choice pour tirer un élément au hasard parmi une liste d'éléments. Ainsi, choice(range(1,7)) choisit au hasard un entier entre 1 et 6 (selon la loi uniforme). Pour simuler un lancer de deux dés il suffit d'additionner deux nombres tirés au hasard de cette façon, comme ci-dessous:


from random import choice
def simul_deux_des():
    return choice(range(1,7))+choice(range(1,7))



# On peut ensuite calculer, lorsqu'on répète n fois l'expérience, la proportion de fois où X a pris chaque valeur, et on peut le comparer aux probabilités obtenues précédemment


def repete_des(n):
    "Cette fonction répète n fois un lancer de dés et calcule la proportion de fois où chaque valeur est tombée"
    nbs=[0]*15# Pour l'instant chaque valeur est "tombée" 0 fois
    for i in range(n):
        v=simul_deux_des()
        nbs[v]=nbs[v]+1 #mise à jour du nombre de fois que la valeur est "tombée"
    return [["","Proportion","Probabilite"]]+[['X='+str(i),(float(nbs[i])/n),proba_des(i)] for i in range(15)]

affiche_tableau(repete_des(200000))


# On constate, lorsque le nombre de lancers de dés est élevé, que les proportions ainsi obtenues sont très proches des probabilités calculées précédemment.



#%% II. Exercices


#%% 1. Lancer de fléchettes

# On considère un rectangle de 2m×2m, au centre duquel se trouve un cible de 1m de rayon. On suppose que l'on lance une fléchette dans le rectangle, selon une loi uniforme.


#%% 1.1) Calcul de probabilité

# Quelle est la probabilité que la fléchette arrive dans le cercle ?
# Enregistrez la dans la variable proba_cercle.



proba_cercle= ....


#%% 1.2) Intérieur du cercle

# Écrire une fonction dans_cercle qui, étant donné deux nombres x et y, détermine si le point de coordonnées (x,y) est à l'intérieur du cercle de centre 0 et de rayon 1.

# Par exemple dans_cercle(0,0.5) devra renvoyer True tandis que dans_cercle(-1,0.5) devra renvoyer False.


def dans_cercle(x,y):




#%% 1.3) Simulation

# Le module random contient aussi une fonction uniform qui permet de simuler une loi uniforme sur un intervalle arbitraire. Ainsi, la position aléatoire de la fléchette s'obtient en choisissant une abscisse et une ordonnée selon la loi uniform(-1,1).
# Ainsi, il suffit d'exécuter dans_cercle(uniform(-1,1),uniform(-1,1)) pour simuler une fléchette aléatoire et déterminer si elle arrive dans le cercle.
# 1. Écrire une fonction simule_flechettes telle que simule_flechettes(n) simule n lancers de fléchettes, et détermine la proportion qui sont arrivées dans la cible.
# 2. Constater que la proportion approche la valeur théorique proba_cercle quand n est très grand.


from random import uniform
def simule_flechettes(n):
    .........


#%% 2. Le Monty Hall

# Monty Hall est le nom du présentateur d'un jeu télévisé où le candidat pouvait gagner une voiture. Il présentait au candidat trois boites dont deux contenaient des chèvres et une contenait la voiture (le présentateur savait laquelle mais pas le candidat). Après que le candidat ait choisit une boite, le présentateur ouvrait une autre boite que celle désignée par le candidat, mais qui contenait une chèvre. Le candidat se voyait alors proposer de choisir la dernière boite ou de conserver son choix initial. Si la boite qu'il choisissait à la fin contenait la voiture, le candidat gagnait la voiture, sinon il perdait.


#%% 2.1) Simulations numériques


# À l'aide de simulations, on souhaite estimer la probabilité de gagner pour un candidat qui change (respectivement pour un candidat qui ne change pas) de boite après qu'on ait ouvert une des boites perdantes.

# 1. Compléter (puis exécuter) le code ci-dessous, pour compter la proportion de gain de candidats qui changent d'avis (et de candidats qui ne changent pas d'avis) au cours d'une simulation.
# 2. En déduire une estimation de la probabilité de gain d'un candidat qui change d'avis, et d'un candidat qui ne change pas d'avis.



def candidat_qui_change():
    bv=choice(range(3)) #boite de la voiture
    bc=choice(range(3)) #boite du candidat
    lb=[] #liste des boites que le présentateur pourrait ouvrir
    for b in range(3):
        if b!=bv and b!=bc:
            lb=lb+[b]
    bo=choice(lb) #boite ouverte par le présentateur
    lb=[] #determinantion de la boite vers laquelle le candidat pourrait changer d'avis
    for b in range(3):
        if .....:
            lb=lb+[b]
    bc=lb[0] #changement d'avis du candidat
    return bc==bv # determine si la boite finale du candidat est celle où se trouve la voiture

def candidat_qui_ne_change_pas():
    ............
    ............
    return bc==bv

def repete_monty_hall(n):
    n1=0 # nombre de succès du candidat qui change
    n2=0 # nombre de succès du candidat qui ne change pas
    for i in range(n):
        if candidat_qui_change():n1=n1+1
        .............
    return (float(n1)/n,float(n2)/n)

print(repete_monty_hall(50000))


#%% 2.2) Calcul de probabilité

# Déterminer par le calcul la probabilité exacte de gain dans chacune des deux situations.



#%% 3. Test de dépistage
# On considère un test de dépistage d'une maladie.
# On suppose que la maladie touche une proportion p₀ de la population.
# On suppose aussi qu'il peut y avoir des erreurs lors du test, à savoir qu'un individu sein a une probabilité e₁ d'être diagnostiqué à tort comme malade, et qu'un individu malade a une probabilité e₂ de ne pas être diagnostiqué comme malade.

# 1. Si un individu est diagnostiqué malade, quelle est la probabilité qu'il soit réellement malade ?   
# Vous la déterminerez par le calcul et comparerez avec des simulations, comme précédemment.
# 2. En particulier commentez le cas d'une maladie rare, pour laquelle p₀=10⁻⁵, e₁=10⁻³, et e₂=10⁻³.
