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

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Este site utiliza o Akismet para reduzir spam. Saiba como seus dados em comentários são processados.