Primeira vez aqui? Seja bem vindo e cheque o FAQ!
x

Programa que simula lançamento de dados. Exercício 3, do Capítulo 3, seção 3.6, na pagina 190 do Livro do Knuth, ”Random Numbers“ do Volume 2 The Art of Computer Programming

+1 voto
158 visitas
perguntada Dez 14, 2020 em Economia por Camilaspinto (21 pontos)  

Escreva um programa que simule um lançamento de dois dados, cada um dos quais assuma os valores 1, 2, ..., 6 com mesma probabilidade.

Se o total for 7 ou 11 no primeiro lançamento, o jogo está ganho; um total de 2, 3 ou 12, o jogo está perdido; e qualquer outro total, chame esse total de "ponto" e continue a lançar os dados até que ocorra um 7 (uma perda) ou o ponto ocorra novamente (uma vitória).

Jogue dez jogos. O resultado de cada lançamento de dados deve ser impresso na forma m n, onde m e n são o conteúdo dos dois dados, seguido por algum comentário apropriado (como "olhos de cobra" ou "pequeno Joe" ou "da maneira mais difícil" , etc.)

Esse exercício 3 está proposto no Livro do Knuth, ”Random Numbers“ do Volume 2 The Art of Computer Programming, no Capítulo 3, seção 3.6, na pagina 190.

Compartilhe

1 Resposta

+1 voto
respondida Dez 14, 2020 por Camilaspinto (21 pontos)  
editado Dez 19, 2020 por Camilaspinto

Conforme enunciado do exercício, já no primeiro lançamento dos dois dados é possível ganhar (soma igual a 7 ou 11) ou perder (soma igual a 2, 3 ou 12). Nas rodadas seguintes, perde-se com um 7 e ganha-se com a repetição de um "point" (resultado do primeiro lançamento quando diferente de 2, 3, 7, 11 ou 12).

Considerando que quando dois dados são lançados há maior probabilidade de a soma ser igual a 7, espera-se verificar maior quantidade de ganhadores já na primeira rodada e maior quantidade de perdedores nas jogadas seguintes.

import numpy as np
from itertools import product 
import matplotlib.pyplot as plt


resultDados = list(product(range(1,7),repeat=2))
somaDados = [sum(i) for i in resultDados] 
x = range(2,13) # a soma varia entre 2 e 12
y = []
y = [somaDados.count(j)/len(resultDados) for j in x]
plt.bar(x,y)

A imagem será apresentada aqui.

Para atender ao solicitado no exercício, foram criadas duas funções, uma para jogar os dados e outra para verificar o resultado de cada lançamento, conforme segue:

import numpy as np
from itertools import product 
import matplotlib.pyplot as plt


def jogaDados():
    '''
    lançam-se dois dados que podem resultar em números de 1 a 6 com a mesma probabilidade 
    '''
    dado1 = np.random.randint(1,7)
    dado2 = np.random.randint(1,7)
    soma = dado1+dado2
    print((dado1, dado2)) # demonstra os resultado de cada dado
    return(soma) # a função retorna a soma dos dados (jogada)


def resultadoJogadas(n_jogadas):
    '''
    Apresenta o resultado de cada jogada até que o jogador ganhe, 
    perca ou o número de jogadas (n_jogadas) se encerre; 
    A função retorna as jogadas (soma dos dados) até o fim do jogo,
    a quantidade de jogadas necessárias para o fim do jogo, 
    bem como se o resultado foi positivo (ganhar=1) ou negativo (perder/chegar ao fim sem ganhar = 0).
    '''
    jogadas = []

    for n in range(1,(n_jogadas+1)):

        print(f'\n{n}ª jogada')
        jogada = jogaDados()

        if n == 1: 
            if (jogada==7) or (jogada==11):
                print(f"Nossa, um {jogada} na primeira rodada, você ganhou!")
                result = 1
                jogadas.append(jogada)
                break

            elif (jogada==2) or (jogada==3) or (jogada==12):
                print(f"Xii, um {jogada} na primeira rodada, você perdeu!")
                result = 0
                jogadas.append(jogada)
                break

            else:
                point = jogada
                print(f'Point: {jogada}')
                jogadas.append(jogada)

        elif n == n_jogadas and (jogada!=7) and (jogada != point):
            print(f'Soma: {jogada}')
            print('Não foi dessa vez!')
            result = 0
            jogadas.append(jogada)

        else:
            print(f'Soma: {jogada}')
            if jogada==7:
                print("Um 7, você perdeu!")
                result = 0
                jogadas.append(jogada)
                break

            elif jogada == point:
                print(f"De novo um point {jogada}, você ganhou!") 
                result = 1
                jogadas.append(jogada)
                break

            else:
                jogadas.append(jogada)

    print("Fim de jogo!\n")
    return([jogadas,n,result])

No momento de chamar as funções, optou-se por simular uma amostra de 1000 jogadores lançando os dados em até 10 vezes para identificar o comportamento dos resultados:

if __name__=='__main__':
    resultados = []
    amostra = 1000
    jogadores = 0
    while jogadores < amostra:
        print(f' ----- Jogador nº {jogadores+1} -----')
        resultados.append(resultadoJogadas(10))
        jogadores += 1
    matriz = resultados
    print(matriz) # A matriz retorna, ao final, os resultados de cada jogador, 
              # sendo o primeiro elemento uma lista com as jogadas (soma dos dados),
              # o segundo elemento o número de jogadas por jogador até o fim do jogo,
              # e o terceiro elemento representa so o jogador ganhou (1) ou perdeu o jogo (0).

Como já esperado, dentre todos os lançamentos dos 1000 jogadores, o resultado mais observado foi o 7, seguindo distribuição próxima da distribuição demonstrada anteriormente:

# list comprehension para consolidar apenas o primeiro elemento da matriz 
# (resultados das jogadas por jogador)
resultadosJogadasPorJogador = [[row[i] for row in matriz] for i in range(3)][0]

# Gráfico indicando os resultados das jogadas (soma dos dados) das 1000 amostras de 
# jogador
x = range(2,13) # a jogada varia entre 2 e 12
y = []
[[y.append(i) for i in lista] for lista in resultadosJogadasPorJogador] 
y = [y.count(j) for j in x]
plt.bar(x,y)

A imagem será apresentada aqui.

Ao se identificar a quantidade total de jogadas necessárias para o fim do jogo, verificou-se que a maior parte dos jogos já se encerra no primeiro lançamento:

# list comprehension para consolidar o segundo elemento da matriz (número total de 
#jogadas por jogador até o fim do jogo)
nJogadasPorJogador =  [[row[i] for row in matriz] for i in range(3)][1]

x = range(1,11) # O número de jogadas pode variar entre 1 e 10
y = []
y = [nJogadasPorJogador.count(j) for j in x]
y
plt.bar(x,y)

A imagem será apresentada aqui.

Ainda que a maior parte dos jogos se encerre no primeiro lançamento (principalmente em função do 7), a maior parte dos jogadores saiu perdendo no jogo (também em função do 7 ter maior probabilidade de aparecer nas nove jogadas seguintes):

# list comprehension para consolidar o terceiro elemento da matriz (resultado do jogo 
#por jogador, onde 1 = ganhar e 0 = perder)
resultadoJogoPorJogador =  [[row[i] for row in matriz] for i in range(3)][2]

x = [0,1] # O número de jogadas pode variar entre 1 e 10
y = []
y = [resultadoJogoPorJogador.count(r) for r in x]
y
plt.bar(x, y,)

A imagem será apresentada aqui.

comentou Dez 18, 2020 por Lucas Lourenço (91 pontos)  
Olá, Camila. Parabéns pela solução, está bastante intuitiva e com frases divertidas no final de cada de jogo!

Note que no primeiro block de código você define um objeto 'teste1' que não foi definido anteriormente, o que retorna erro. Acredito que a ideia seria termos 'somaDados' no lugar, certo?

Fiz também um exercício para vermos as probabilidades de vitória/derrota em cada round do jogo. À lá Bayes, saberemos a probabilidade de vitória dado que o jogo terminou na rodada i. Para não usarmos a fórmula, podemos calcular essas probabilidades (experimento de Monte Carlo?). Caso se interesse, segue o código. Mas é só uma sugestão simples. Parabéns pelo trabalho!

 
vitorias = {}
derrotas ={}
partidas = {}

for i in range (1,21):
    vitorias[i] = 0
    derrotas[i] = 0
    partidas[i] = 0
for i in range(10000):
    result = resultadoJogadas(20)
    partidas[result[1]] += 1
    if result[-1] == 1:
        vitorias[result[1]] += 1
    elif result[-1] == 0:
        derrotas[result[1]] += 1

x_axis = []
v=[]
d=[]
for i in partidas:
    x_axis.append(i)
    try:
        v.append(vitorias[i]/partidas[i])
        d.append(derrotas[i]/partidas[i])
    except:
        v.append(0)
        d.append(0)

plt.plot(x_axis,v)   
plt.plot(x_axis,d)
comentou Dez 19, 2020 por Camilaspinto (21 pontos)  
Oi Lucas, de fato, onde você indicou deveria ser somaDados mesmo. Fiz a correção, obrigada!
Agradeço também sua sugestão de código. O rodei aqui algumas vezes e por meio dos gráficos gerados foi possível perceber que se o jogador não ganha na primeira rodada (probabilidade próxima de 70%), ao longo do jogo há probabilidade maior em perder.
...