from random import random
from math import floor, sqrt
import matplotlib.pyplot as plt

## Exercice 1 — Loi uniforme maison

def monrandint(n, m):
    # On découpe [0, 1] en m-n+1 intervalles de même longueur.
    return n + floor((m - n + 1) * random())

# Environ 100000 / 6 ≈ 16667 fois le 6.
# cpt = 0
# for i in range(100000):
#     if monrandint(1, 6) == 6:
#         cpt = cpt + 1
# print(cpt)


## Exercice 2 — Bernoulli et binomiale

def bernoulli(p):
    if random() < p:
        return 1
    return 0

def binomiale(n, p):
    s = 0
    for i in range(n):
        s = s + bernoulli(p)
    return s

def bernoulli_liste(p, k):
    return [bernoulli(p) for i in range(k)]

def binomiale_liste(n, p, k):
    return [binomiale(n, p) for i in range(k)]

def effectifs_binomiale(n, p, k):
    L = (n + 1) * [0]
    for i in range(k):
        x = binomiale(n, p)
        L[x] = L[x] + 1
    return L

# n, p, k = 10, 0.3, 10000
# L = effectifs_binomiale(n, p, k)
# plt.bar([i for i in range(n + 1)], L)
# plt.show()


## Exercice 3 — Simulation d'une loi discrète quelconque

def cumsum(L):
    Lp = []
    s = 0
    for x in L:
        s = s + x
        Lp.append(s)
    return Lp

def indice(L, x):
    s = 0
    for k in range(len(L)):
        if s <= x < s + L[k]:
            return k
        s = s + L[k]
    return len(L) - 1

def simule(valeurs, probas):
    return valeurs[indice(probas, random())]

# 20 chevaux équiprobables : P(1er) = P(2e) = P(3e) = 1/20, sinon 17/20.
# Gain net = gain - mise.

def gain():
    return simule([90, 40, 10, -10], [1 / 20, 1 / 20, 1 / 20, 17 / 20])

def gains(k):
    return [gain() for i in range(k)]

def esperance_gain(k):
    s = 0
    for i in range(k):
        s = s + gain()
    return s / k

def variance_gain(k):
    s = 0
    s2 = 0
    for i in range(k):
        g = gain()
        s = s + g
        s2 = s2 + g * g
    m = s / k
    return s2 / k - m * m

# Espérance théorique : 90/20 + 40/20 + 10/20 - 10*17/20 = -1.5
# Le jeu est défavorable au joueur.


## Exercice 4 — Boîtes d'allumettes

def simule_X():
    pile = 20
    face = 20
    while pile > 0 and face > 0:
        if random() < 0.5:
            pile = pile - 1
        else:
            face = face - 1
    return pile + face

def simuleMFois(m):
    L = 20 * [0]
    for i in range(m):
        x = simule_X()
        L[x - 1] = L[x - 1] + 1
    return L

def moyenne_empirique(L, m):
    s = 0
    for i in range(20):
        s = s + (i + 1) * L[i]
    return s / m

def ecart_type_empirique(L, m):
    mu = moyenne_empirique(L, m)
    s2 = 0
    for i in range(20):
        s2 = s2 + (i + 1) ** 2 * L[i]
    return sqrt(s2 / m - mu ** 2)

# L = simuleMFois(2000)
# print(moyenne_empirique(L, 2000), ecart_type_empirique(L, 2000))
# plt.bar([k for k in range(1, 21)], L)
# plt.show()
