# primeiro exemplo de repetição condicional: loop infinito!

# while True:
#     print("Professor, já corrigiu a prova?")
# loop ou laço infinito! Use ctrl-c para matar a execução

# Brincando com coisas aleatórias do módulo random

from random import randrange

# Vamos testar se o randrange é "justo"


def contador_de_resultados_dado_6(quantidade_repetições=10**6):
    """Sorteia um número inteiro aleatório de 1 a 6 (inclusive)
    quantidade_repetições (inteiro) vezes e conta quantas vezes
    cada um foi sorteado, retornando em um dicionário"""

    contagens = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0}
    jogadas = 0

    while jogadas < quantidade_repetições:
        sorteio = randrange(1, 6 + 1)

        # contagens[sorteio] = contagens[sorteio] + 1
        contagens[sorteio] += 1
        jogadas += 1

    return contagens


def porcentagens_de_resultados_dado_6(quantidade_repetições=10**6):
    """
    Retorna um dicionário com as porcentagens dos sorteios das faces
    de um dado de 6 faces, repetidos quantidade_repetições (inteiro)
    de vezes"""
    contagens = contador_de_resultados_dado_6(quantidade_repetições)
    porcentagens = {
        1: 100 * contagens[1] / quantidade_repetições,
        2: 100 * contagens[2] / quantidade_repetições,
        3: 100 * contagens[3] / quantidade_repetições,
        4: 100 * contagens[4] / quantidade_repetições,
        5: 100 * contagens[5] / quantidade_repetições,
        6: 100 * contagens[6] / quantidade_repetições
        }

    return porcentagens

def porcentagens_de_resultados_dado_6_não_se_repita(quantidade_repetições=10**6):
    """
    Retorna um dicionário com as porcentagens dos sorteios das faces
    de um dado de 6 faces, repetidos quantidade_repetições (inteiro)
    de vezes"""
    contagens = contador_de_resultados_dado_6(quantidade_repetições)
    porcentagens = {}

    face_atual = 1
    while face_atual <= 6:
        porcentagens[face_atual] = 100*contagens[face_atual]/quantidade_repetições
        face_atual += 1

    return porcentagens

# Vamos ver quantas vezes (espera-se) temos que sortear um D6 até sair uma face específica

def sorteios_de_D6_até_sair(face_desejada):
    """
    Retorna a quantidade de sorteios de um D6
    até que saia a face_desejada (inteiro de 1 a 6)
    """
    # "jogar o dado e anotar a contagem até sair"
    contagem = 1
    while randrange(1,6+1) != face_desejada:
    # while not (randrange(1,6+1) == face_desejada):
        contagem += 1
    return contagem
    
def média_sorteios_de_D6_até_sair(face_desejada, quantidade_repetições=10**6):
    """
    Retorna a média [...]
    """
    quantidade = 0
    soma = 0
    while quantidade < quantidade_repetições:
        soma += sorteios_de_D6_até_sair(face_desejada)
        quantidade += 1
    return soma/quantidade_repetições

#################################
################################# GENERALIZANDO
#################################

def contador_de_resultados(quantidade_faces, quantidade_repetições=10**6):
    """Sorteia um número inteiro aleatório de 1 a quantidade_faces (inteiro)
    quantidade_repetições (inteiro) vezes e conta quantas vezes
    cada um foi sorteado, retornando em um dicionário"""

    contagens = {}
    face_atual = 1
    while face_atual <= quantidade_faces:
        contagens[face_atual] = 0
        face_atual += 1
    
    jogadas = 0

    while jogadas < quantidade_repetições:
        sorteio = randrange(1, quantidade_faces + 1)

        # contagens[sorteio] = contagens[sorteio] + 1
        contagens[sorteio] += 1
        jogadas += 1

    return contagens

####### Controle "manual" de iterações: continue e break
####### continue: "passe para a próxima iteração"
####### break: "saia da repetição"


def sorteios_de_D6_até_sair_retornando_sorteios(face_desejada):
    """
    Retorna a quantidade de sorteios de um D6
    até que saia a face_desejada (inteiro de 1 a 6)
    """
    # "jogar o dado e anotar as faces que saem até sair a desejada"
    faces_que_saíram = []

    sorteio_atual = randrange(1,6+1)
    while sorteio_atual != face_desejada:
        faces_que_saíram.append(sorteio_atual)
        sorteio_atual = randrange(1,6+1) # fere o princípio "não se repita"

    return faces_que_saíram

def sorteios_de_D6_até_sair_retornando_sorteios_não_se_repita(face_desejada):
    """
    Retorna a quantidade de sorteios de um D6
    até que saia a face_desejada (inteiro de 1 a 6)
    """
    # "jogar o dado e anotar as faces que saem até sair a desejada"
    faces_que_saíram = []

    while True:
        sorteio_atual = randrange(1,6+1)
        if sorteio_atual == face_desejada:
            break
        faces_que_saíram.append(sorteio_atual)

    return faces_que_saíram

######
######

def faces_pares_sorteadas_D6_até(face_desejada):
    """
    Faz sorteios de D6 até que saia face_desejada (inteiro de 1 a 6)
    e retorna a lista das faces pares sorteadas (excluindo a face_desejada)
    """
    faces_pares_sorteadas = []
    while True:
        sorteio_atual = randrange(1,6+1)
        if sorteio_atual == face_desejada:
            break
        # if sorteio_atual %2 == 0:
        #     faces_pares_sorteadas.append(sorteio_atual)
        if sorteio_atual %2 != 0:
            continue
        faces_pares_sorteadas.append(sorteio_atual)
    return faces_pares_sorteadas

###### Exemplo da matemática: algoritmo de Euclides para calcular mdc: 300 b.C.
# Divisões repetidas!

def mdc_Euclides(a,b):
    """Dados inteiros positivos a,b retorna seu maior divisor comum"""
    dividendo = a
    divisor = b
    resto = dividendo % divisor
    contador = 1
    while resto != 0:
        dividendo, divisor = divisor, resto
        resto = dividendo % divisor
        contador += 1
    return divisor, contador
    
def mdc_Euclides_não_se_repita(a,b):
    """Dados inteiros positivos a,b retorna seu maior divisor comum"""
    dividendo = a
    divisor = b
    contador = 0
    while True:
        resto = dividendo % divisor
        contador += 1
        if resto == 0:
            break
        dividendo, divisor = divisor, resto
    return divisor, contador
    
##################
# Sequência de Fibonacci
# 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...

def fibo(n):
    """
    Retorna o n-ésimo número de Fibonacci (n inteiro, assumindo n > 2)
    """
    penúltimo = 0
    último    = 1
    contador  = 2
    while contador < n:
        atual = penúltimo + último
        penúltimo, último = último, atual
        contador += 1
    return atual

def primeiro_fibo_maior_que(n):
    """
    Retorna o primeiro número de Fibonacci maior ou igual a n (inteiro, assumindo
    n >= 2)
    """
    # gerar números de Fibonacci até ver algum >= n
    # gerar números de Fibonacci enquanto forem menores que n
    posição_atual = 3
    while True:
        fibo_atual = fibo(posição_atual)

        if fibo_atual >= n:
            break
        
        posição_atual += 1
    return fibo_atual
