Neste desafio, você jogará o dilema do prisioneiro ruidoso e iterado.
O dilema do prisioneiro é um cenário na teoria dos jogos em que existem dois jogadores, cada um com duas opções: cooperar ou defeito. Cada jogador se sai melhor se desertar do que cooperar, mas ambos preferem o resultado em que os dois cooperam com aquele em que os dois desertam.
O dilema do prisioneiro iterado é o mesmo jogo, exceto que você joga contra o mesmo oponente repetidamente e sabe o que o seu oponente jogou no passado. Seu objetivo é sempre acumular a maior pontuação para si mesmo, independentemente de como o seu oponente o faz.
O dilema ruidoso do prisioneiro iterado introduz algum ruído na comunicação. Seu conhecimento do que seu oponente jogou no passado terá algum ruído introduzido. Você também saberá quais movimentos você fez no passado. A taxa de ruído é constante durante uma rodada contra o mesmo oponente, mas diferente entre rodadas diferentes.
Desafio
Neste desafio, você escreverá um programa Python 3 para reproduzir o dilema ruidoso do prisioneiro iterado.
Seu programa receberá três entradas:
Seus próprios movimentos, sem movimentos aleatórios aplicados.
Os movimentos do seu oponente, com movimentos aleatórios aplicados.
Uma variável de estado, que começa como uma lista vazia a cada rodada e que você pode modificar se desejar. Você pode ignorar isso se não quiser usá-lo.
Seu programa deve produzir 'c'
para cooperar ou 'd'
desertar.
Por exemplo, aqui está um programa que coopera se o oponente cooperou pelo menos 60% do tempo no passado, após a aplicação de movimentos aleatórios e nos 10 primeiros movimentos:
def threshold(my_plays, their_flipped_plays, state):
if len(their_flipped_plays) < 10:
return 'c'
opp_c_freq = their_flipped_plays.count('c')/len(their_flipped_plays)
if opp_c_freq > 0.6:
return 'c'
else:
return 'd'
Se você não conhece o Python, escreva sua submissão em pseudocódigo, e alguém (eu ou outro membro do site) pode criar o programa Python correspondente.
Jogabilidade
O corredor do torneio pode ser encontrado aqui: jogo barulhento . Corra noisy-game.py
para executar o torneio. Manterei esse repositório atualizado com novos envios. Programas de exemplo podem ser encontrados em basic.py
.
A pontuação geral de um programa é o total de sua pontuação em mais de 100 jogadas.
Um jogo consiste em confrontos round-robin de cada jogador contra cada jogador, incluindo ele próprio. Uma partida consiste em 100 rodadas. Uma rodada consiste em 300 jogadas, cada uma das quais envolve saída 'c'
ou 'd'
.
Seu envio fará uma comparação com todos os envios, incluindo o seu. Cada confronto será composto de 100 rodadas. Durante cada rodada, uma probabilidade de inversão será escolhida uniformemente aleatoriamente [0, 0.5]
.
Cada rodada consistirá em 300 jogadas. Em cada movimento, os dois programas receberão todas as reproduções anteriores que tentaram e todas as reproduções anteriores que o outro programa fez, após a aplicação dos lançamentos, e uma variável de estado, que é uma lista mutável que o programa pode modificar, se desejar. Os programas produzirão seus movimentos.
Os movimentos são pontuados da seguinte forma: Se um programa toca a 'c'
, o programa adversário recebe 2 pontos. Se um programa toca a 'd'
, esse programa recebe 1 ponto.
Então, cada movimento é invertido independentemente, com probabilidade igual à probabilidade de inverter, e armazenado para exibição ao oponente.
Depois que todas as rodadas foram disputadas, somamos o número de pontos que cada jogador obteve em cada partida. Em seguida, usamos o seguinte sistema de pontuação para calcular a pontuação de cada jogador para o jogo. Essa pontuação é realizada após a conclusão de todos os confrontos.
Pontuação
Usaremos a pontuação evolutiva. Cada programa começa com o mesmo peso. Em seguida, os pesos são atualizados da seguinte forma, para 100 iterações, usando os totais de pontos do jogo:
O novo peso de cada programa é proporcional ao produto do seu peso anterior e ao seu total médio de pontos, ponderado pelos pesos de seus oponentes.
São aplicadas 100 atualizações desse tipo e os pesos finais são a pontuação de cada programa para a execução do jogo.
A pontuação geral será a soma de mais de 100 corridas do jogo.
Os jogadores terão todas as respostas válidas para esse desafio, além de seis programas básicos para começar.
Ressalvas
Não modifique as entradas. Não tente afetar a execução de nenhum outro programa, exceto através da cooperação ou defeito. Não faça uma submissão sacrificial que tente reconhecer outra submissão e beneficiar esse oponente às suas próprias custas. As brechas padrão são proibidas.
EDIT: Os envios não podem duplicar exatamente nenhum dos programas básicos ou envios anteriores.
Se você tiver alguma dúvida não hesite em perguntar.
Resultados atuais
nicht_genug: 40.6311
stealer: 37.1416
enough: 14.4443
wait_for_50: 6.947
threshold: 0.406784
buckets: 0.202875
change_of_heart: 0.0996783
exploit_threshold: 0.0670485
kickback: 0.0313357
tit_for_stat: 0.0141368
decaying_memory: 0.00907645
tit_for_whoops: 0.00211803
slider: 0.00167053
trickster: 0.000654875
sounder: 0.000427348
tit_for_tat: 9.12471e-05
stubborn_stumbler: 6.92879e-05
tit_for_time: 2.82541e-05
jedi2sith: 2.0768e-05
cooperate: 1.86291e-05
everyThree: 1.04843e-05
somewhat_naive: 4.46701e-06
just_noise: 1.41564e-06
growing_distrust: 5.32521e-08
goldfish: 4.28982e-09
vengeful: 2.74267e-09
defect: 3.71295e-10
alternate: 2.09372e-20
random_player: 6.74361e-21
Resultados com apenas respostas a esta pergunta e programas básicos que ignoram a jogada do oponente:
nicht_genug: 39.3907
stealer: 33.7864
enough: 20.9032
wait_for_50: 5.60007
buckets: 0.174457
kickback: 0.0686975
change_of_heart: 0.027396
tit_for_stat: 0.024522
decaying_memory: 0.0193272
tit_for_whoops: 0.00284842
slider: 0.00153227
sounder: 0.000472289
trickster: 0.000297515
stubborn_stumbler: 3.76073e-05
cooperate: 3.46865e-05
tit_for_time: 2.42263e-05
everyThree: 2.06095e-05
jedi2sith: 1.62591e-05
somewhat_naive: 4.20785e-06
just_noise: 1.18372e-06
growing_distrust: 6.17619e-08
vengeful: 3.61213e-09
goldfish: 3.5746e-09
defect: 4.92581e-10
alternate: 6.96497e-20
random_player: 1.49879e-20
Ganhando
A competição permanecerá aberta indefinidamente, à medida que novos envios forem publicados. No entanto, declararei um vencedor (aceite uma resposta) com base nos resultados 1 mês após a postagem desta pergunta.
exploit_threshold()
várias vezes como exploit_threshold1()
, etc e os adicionei à players
lista. Por que obtenho resultados muito diferentes para estratégias idênticas?