# simulation de Bernoulli, d'une loi binimale comme somme de Bernoulli
from random import *
from math import *
from matplotlib.pyplot import *
from numpy import linspace


def  u(): # simule un nombre réel entre 0 et 1
   return(random())
   
def F_u(x,nb): # Que fait cette fonction?
    c=0
    for j in range(nb):
        tirage=u()
        if tirage<=x:
            c=c+1
    return c/nb
        

def trace_u(nb): # Que fait cette fonction?
   LX=linspace(-1,2,500)
   print(len(LX))
   LY=[F_u(p,nb) for p in LX]
   plot(LX,LY)
   show()


# Q_3 #########################################☺
def  ber(p):   #tirage de Bernoulli  b(p)=B(p)
   tirage=random()
   if tirage<p:
      return 1
   else:
      return 0

# Q_4 #########################################☺


def  bino(n,p): # S simule la somme de n épreuve de Bernoulli B(p)
  somme=0
  for i in range(n):
     somme=somme+ber(p)
  return somme

def binoT(k,n,p):  #binomiale théorique bino(n,p)=B(n,p)
   return factorial(n)/factorial(k)/factorial(n-k)*p**k*(1-p)**(n-k)


### Vérifiaction expérimentale(début)
def listebinoT(n,p): # liste théorique des probabilités de B(n,p)
   c=(n+1)*[0]
   for k in range(n+1):
      c[k]=binoT(k,n,p)
   return c


def Verification(n,p,nb): # on simule nb tirage de S puis on compte le nb de fois 
                       # où S=k et on renvoie la liste des différences entre 
                       # les proba simulées et théoriques : P(S=k),k=0..n                          
  L=nb*[0]
  for i in range(nb):
     L[i]=bino(n,p)
  c=(n+1)*[0]
  for i in range(nb):
    for k in range(n+1):
       if L[i]==k:
          c[k]=c[k]+1
  for k in range(n+1):
      c[k]=c[k]/nb
  cc=listebinoT(n,p) 
  return [c[i]-cc[i] for i in range(n+1)] 

### Vérifiaction expérimentale(fin)
   
   
# Q_5 #########################################☺
   
def geo(p):
   tirage=random()
   essai=1
   while  tirage>=p:
      tirage=u()
      essai+=1
   return essai
   


# Q_6 #########################################☺   
def geoS(p,k,nb):
   s=0
   for n in range(nb):
      tirage=geo(p)
      if tirage==k:
         s=s+1
   return [s/nb,p*(1-p)**(k-1)]

# Q_7  #########################################☺
def espS(p,nb):
   s=0
   for n in range(nb):
      s=s+geo(p)
   return s/nb

def esp2(p,nb): # espérance de X^2
   s=0
   for n in range(nb):
      s=s+geo(p)**2
   return s/nb
  
def V(p,nb):
   return [esp2(p,nb)-espS(p,nb)**2,(1-p)/p**2]
    
# VIGNETTE - VIGNETTE - VIGNETTE - VIGNETTE - 
# Q_9 #########################################☺
def collec():
    nbt=0 # nombre de tablettes
    nbj=0 # nombre d'images de joueurs
    C=15*[0] # tableau des images
    while nbj<15:
        
        nbt+=1 # une tablette de plus achetée
        aux=randint(0,14)
        if C[aux]==0:
            nbj+=1 # un joueur de plus dans la collec
            C[aux]=1 # on colle l'image dans son tableau
        
    return(nbt) # retourne le nb de tablette achetées pour avoir les 15 images

def parent(nb): # espérance simulée
    s=0
    for i in range(nb):
        s=s+collec()
    return(s/nb)
        

def espVignetteTheorique(): # espèrance théorique 
    s=0
    for i in range(1,16):
        s=s+1/i
    return(15*s) # 

def esp2Vignette(nb): # espérance de X^2 simulée 
    s=0
    for i in range(nb):
        s=s+collec()**2
    return(s/nb)
   

def var(nb): # variance simulée 
    return(esp2Vignette(nb)-parent(nb)**2)

def varTheorique(): # variance  théorique 
    s=0
    for i in range(1,16):
       p=(15-i+1)/15
       q=1-p
       s=s+q/p**2
    return(s) 

# TENNIS - TENNIS - TENNIS - TENNIS - TENNIS - 
# Q_11 #########################################☺
def jeu(p): #renvoie 1 si 'A' gagne le jeu et 0 si 'B' gagne
    points_A=0;points_B=0
    for i in range(6):
        aux=ber(p)
        if aux==1:
            points_A +=1
        else:
            points_B +=1
        if points_A==4:
            return(1)
        if points_B==4:
            return(0)
    while abs(points_B-points_A)<=1:
        aux=ber(p)
        if aux==1:
            points_A +=1
        else:
            points_B +=1
     #   print(points_A,points_B)
    #print('jeu')
    if points_A>points_B:
        return(1)
    else:
        return(0)
        
      
# Q_12 #########################################☺
def f(p,nb): # renvoi statistiquement la proba. de  jeu(p)
    c=0
    for i in range(nb):
        c=c+jeu(p)
    return(c/nb)

def fT(p): # valeur de la probabilité exacte de jeu(p)
   return (15*p**4-34*p**5+28*p**6-8*p**7)/(1-2*p+2*p**2)

# Q_13 #########################################☺
def traceTennis():
   LX=linspace(0,1,500)
   LY=[f(p,5000) for p in LX]
   plot(LX,LY)
   show()
   
   
#SCRUTIN-------------------------------
# Q_14  ##########################################
def depouillement():
    L=[1 for i in range(600)]+[0 for i in range(400)]
    nbA=0
    nbB=0
    while len(L)>0:
        i=randint(0,len(L)-1)
        if L[i]==1:
            nbA=nbA+1
        else:
            nbB=nbB+1
        if nbB>=nbA:
            return 0
        L.remove(L[i]) #on retire le bulletin étudié
    return 1

def probaScrutin(nb):
    s=0
    for i in range(nb):
        tirage=depouillement()
        s=s+tirage
    return(s/nb)

