Explicação sobre aleatoriedade – aplicação com o Dilema do Prisioneiro
Muitas vezes geração de números aleatórios é explicada a partir de jogar uma moeda ou de um dado (eu mesmo já fiz isso aqui), embora seja interessante explicar com outras aplicações, como eu mesmo já fiz associando com o problema de Monty Hill. Dessa vez explico a aleatoriedade a partir da elaboração de uma simulação para o Dilema do Prisioneiro. Inicialmente explico todo o dilema e depois faço códigos para a simulação.
O Dilema do Prisioneiro é um conceito da Teoria dos Jogos que ilustra a dificuldade em se obter cooperação entre dois indivíduos, mesmo que a colaboração mútua gere o melhor resultado para ambos. O dilema demonstra como a busca pelo interesse próprio pode levar a um desfecho desfavorável para todos os envolvidos.
A essência do problema reside em um cenário hipotético envolvendo dois prisioneiros, cúmplices de um crime, que são presos e mantidos em celas separadas, sem qualquer meio de comunicação. A polícia não possui provas suficientes para condená-los pelo crime principal, apenas por uma ofensa menor. Aos dois prisioneiros é oferecido o mesmo acordo, e as consequências de suas decisões são interdependentes.
A situação pode ser resumida da seguinte forma:
- Se ambos os prisioneiros confessarem (traírem um ao outro): Ambos receberão uma pena moderada, por exemplo, 5 anos de prisão cada.
- Se ambos os prisioneiros permanecerem em silêncio (cooperarem um com o outro): Ambos serão condenados pela ofensa menor e receberão uma pena leve, por exemplo, 1 ano de prisão cada.
- Se um prisioneiro confessar (trair o outro) e o outro permanecer em silêncio: O que confessou será libertado, enquanto o que permaneceu em silêncio receberá uma pena severa, por exemplo, 10 anos de prisão.
O diagrama mostra que, independentemente da escolha do seu cúmplice, a sua melhor opção individual é sempre trair. Você ou sai livre ou pega uma pena menor do que pegaria se cooperasse:
- Se o Prisioneiro B ficar em silêncio: A melhor opção para o Prisioneiro A é confessar, pois assim ele sairá livre em vez de cumprir 1 ano de prisão.
- Se o Prisioneiro B confessar: A melhor opção para o Prisioneiro A é também confessar, pois assim ele pegará 5 anos em vez dos 10 que pegaria se ficasse em silêncio.
Como ambos os prisioneiros seguem a mesma lógica racional, ambos acabam confessando e recebendo uma pena de 5 anos cada. Este resultado é conhecido como Equilíbrio de Nash, um estado em que nenhum jogador pode melhorar sua situação mudando sua estratégia unilateralmente.
O paradoxo é que, se ambos tivessem cooperado (ficado em silêncio), teriam obtido um resultado muito melhor para o grupo (apenas 1 ano de prisão cada). A busca pelo melhor resultado individual leva a um resultado coletivo pior.
Simulação do Dilema do Prisioneiro
Para simulação, vou considerar 2 cenários:
- Prisioneiros Aleatórios: cada agente não tem um estratégia e “sorteia” que irá fazer. Considerei que em 80% das vezes ele irá decidir baseado na mesma lógica racional (que seria confessar), mas recomendo que experimente outros valores.
- Estratégia “Olho por Olho” (Tit-for-Tat): Os prisioneiros são cooperativos. Eles começam cooperando na primeira rodada e a partir da segunda rodada, cada prisioneiro simplesmente copia a jogada anterior do seu oponente. Se o oponente cooperou na rodada passada, ele coopera. Se o oponente traiu, ele trai. Logicamente que, se ambos iniciam cooperando e depois seguem repetindo o anterior, eles irão cooperar do começo ao fim, por isso coloquei que cada prisioneiro tem 80% de chance trair seu companheiro.
import random
# --- Constantes para as escolhas ---
# Usar números facilita a lógica, mas as constantes tornam o código mais legível.
COOPERAR = 0
TRAIR = 1 # O mesmo que "confessar"
# --- Configurações da Simulação ---
NUMERO_DE_RODADAS = 1000
PROBABILIDADE_TRAIR = 0.8 # 80% de chance de trair no cenário aleatório e no modificado
def dilema_do_prisioneiro(escolha_p1, escolha_p2):
"""
Calcula a sentença para cada prisioneiro com base em suas escolhas.
Retorna uma tupla com (sentença_p1, sentença_p2).
"""
if escolha_p1 == COOPERAR and escolha_p2 == COOPERAR:
# Ambos cooperam: pena branda para os dois.
return (1, 1)
elif escolha_p1 == COOPERAR and escolha_p2 == TRAIR:
# P1 coopera, P2 trai: P1 recebe a pena máxima, P2 sai livre.
return (10, 0)
elif escolha_p1 == TRAIR and escolha_p2 == COOPERAR:
# P1 trai, P2 coopera: P1 sai livre, P2 recebe a pena máxima.
return (0, 10)
elif escolha_p1 == TRAIR and escolha_p2 == TRAIR:
# Ambos traem: pena intermediária para os dois.
return (5, 5)
def simular_cenario_aleatorio():
"""
Simula o dilema com prisioneiros que decidem de forma aleatória,
com uma tendência de 80% a trair.
"""
total_anos_p1 = 0
total_anos_p2 = 0
for _ in range(NUMERO_DE_RODADAS):
# Cada prisioneiro decide trair com 80% de probabilidade.
escolha_p1 = TRAIR if random.random() < PROBABILIDADE_TRAIR else COOPERAR
escolha_p2 = TRAIR if random.random() < PROBABILIDADE_TRAIR else COOPERAR
sentenca_p1, sentenca_p2 = dilema_do_prisioneiro(escolha_p1, escolha_p2)
total_anos_p1 += sentenca_p1
total_anos_p2 += sentenca_p2
return total_anos_p1, total_anos_p2
def simular_olho_por_olho_com_traicao():
# Simula "Olho por Olho" onde P1 tem 80% de chance de trair
total_anos_p1 = 0
total_anos_p2 = 0
jogada_anterior_p1 = COOPERAR
jogada_anterior_p2 = COOPERAR
for i in range(NUMERO_DE_RODADAS):
# P2 joga "Olho por Olho" puro
escolha_p2 = jogada_anterior_p1 if i > 0 else COOPERAR
# Lógica de P1
if i > 0 and jogada_anterior_p1 == TRAIR: #se antes P1 traiu ele volta atrás
escolha_p1 = COOPERAR
else:
# P1 não traiu, então verifica a chance de trair agora
if random.random() < PROBABILIDADE_TRAIR:
escolha_p1 = TRAIR
else:
escolha_p1 = COOPERAR
sentenca_p1, sentenca_p2 = dilema_do_prisioneiro(escolha_p1, escolha_p2)
total_anos_p1 += sentenca_p1
total_anos_p2 += sentenca_p2
jogada_anterior_p1 = escolha_p1
jogada_anterior_p2 = escolha_p2
return total_anos_p1, total_anos_p2
if __name__ == "__main__":
# Cenário 1: Prisioneiros escolhendo de forma aletória
anos_p1_aleatorio, anos_p2_aleatorio = simular_cenario_aleatorio()
total_geral_aleatorio = anos_p1_aleatorio + anos_p2_aleatorio
print("--- Cenário 1: Prisioneiros Aleatórios (80% de chance de trair) ---")
print(f"Total de anos para o Prisioneiro 1: {anos_p1_aleatorio}")
print(f"Total de anos para o Prisioneiro 2: {anos_p2_aleatorio}")
print(f"Total geral de anos de prisão: {total_geral_aleatorio}\n")
# Cenário 2: "Olho por Olho" com Tendência à Traição
anos_p1_mod, anos_p2_mod = simular_olho_por_olho_com_traicao()
total_geral_mod = anos_p1_mod + anos_p2_mod
print("--- Cenário 2: 'Olho por Olho' com 80% de Chance de Trair ---")
print(f"Total de anos para o Prisioneiro 1: {anos_p1_mod}")
print(f"Total de anos para o Prisioneiro 2: {anos_p2_mod}")
print(f"Total geral de anos de prisão: {total_geral_mod}\n")
Ao rodar o código, observe que o total de anos preso de cada prisioneiro é sempre menor no segundo cenários. O resultado da execução é ilustrado abaixo. Se quiser fazer usas próprias execuções, acesse o código aqui.
--- Cenário 1: Prisioneiros Aleatórios (80% de chance de trair) ---
Total de anos para o Prisioneiro 1: 4816
Total de anos para o Prisioneiro 2: 4776
Total geral de anos de prisão: 9592
--- Cenário 2: 'Olho por Olho' com 80% de Chance de Trair ---
Total de anos para o Prisioneiro 1: 4552
Total de anos para o Prisioneiro 2: 4552
Total geral de anos de prisão: 9104