Entre os melhores
154 Calculator
144 Taxman
138 Statistician
137 Solver
137 RandoAggroLawyer
136 Gambler
134 Turncoat
119 Lawyer
119 BloodyMurder
113 Bandit
79 Challenger
74 Mask
64 Random
Um arquivo da última correspondência, incluindo o log e todos os arquivos de saída, está disponível.
Calculator, de Brilliand, é o vencedor! Sua resposta é aceita, mas isso não significa que o desafio acabou. Sinta-se livre para enviar novas entradas ou editar as atuais e tentar derrubá-lo de seu trono. Atribuirei uma recompensa ao líder no final do mês.
Regras do Jogo
Coup é um jogo de cartas projetado para 2-6 jogadores, com o qual jogaremos com dois. Consiste em um tesouro de moedas (infinito para nossos propósitos) e um baralho de 15 cartas, contendo 3 de cada um dos seguintes tipos: Embaixador, Assassino, Capitão, Contessa, Duke. No início do jogo, cada jogador recebe uma moeda e distribui duas cartas aleatoriamente, que mantêm em segredo até necessário. O objetivo é ser o último jogador com cartas na sua mão.
Por sua vez, um jogador pode executar uma das seguintes ações, independentemente de suas cartas:
- Renda: pegue 1 moeda do tesouro. Inbloqueável e inquestionável.
- Ajuda externa: pegue 2 moedas do tesouro. Pode ser bloqueado por um jogador com um duque. Incontestável.
- Golpe: Retire uma carta de um oponente de sua escolha do jogo. Custa 7 moedas. A vítima pode escolher qual cartão descartar. Se um jogador tiver 10 ou mais moedas no início do seu turno, ele deve golpe. Inbloqueável e inquestionável.
Dependendo das cartas, os jogadores também podem realizar uma das seguintes ações no turno:
- Troca: um jogador com um Embaixador pode pegar duas cartas do baralho. Depois, eles podem escolher, entre as mãos e as cartas sorteadas, quantas cartas originalmente tinham. (Ou seja, se eles tivessem apenas uma carta, poderiam trocá-la por uma das cartas compradas ou mantê-la, e se tivessem duas cartas, poderiam escolher qualquer uma das quatro cartas.) As duas cartas indesejadas são devolvidas ao baralho. . Unblockable, mas desafiável.
- Assassino: um jogador com um Assassino pode gastar 3 moedas para remover a carta do oponente do jogo. A vítima pode escolher qual cartão descartar. Pode ser bloqueado por um jogador com uma Contessa. Nesse caso, as moedas não são devolvidas. Desafiável, caso em que as moedas são devolvidas.
- Roubar: Um jogador com um capitão pode receber duas moedas do oponente. Se o oponente tiver uma moeda, eles receberão a mesma moeda. Se o oponente tiver zero moedas, ele não poderá roubar. Pode ser bloqueado por um jogador com um embaixador ou um capitão. Desafiavel.
- Imposto: Um jogador com um duque pode receber 3 moedas do tesouro. Unblockable, mas desafiável.
A parte complicada do golpe é que os jogadores podem mentir sobre quais cartas eles têm! Não é necessário ter um cartão para tentar executar a ação ou bloquear associado a ele.
Quando um jogador executa a ação de uma carta, qualquer oponente (mesmo aquele que não é prejudicado por essa ação) pode desafiar o ator e dizer que não acredita ter a carta para essa ação. Se o desafiante estiver correto, a ação será cancelada e o ator deverá descartar uma carta de sua escolha (recuperando todas as moedas que gastou, se aplicável). Caso contrário, a ação é tomada, o ator devolve a carta que foi desafiada para o baralho e compra uma nova, e o desafiante deve descartar uma de suas cartas. Os jogadores devem ser sinceros quanto às cartas que possuem quando desafiadas.
Cartas eliminadas do jogo com Assassinate, Coup e desafios perdidos não são devolvidas ao baralho, mas as cartas reveladas como parte de um desafio vencido são devolvidas ao baralho.
Blocos podem ser desafiados como ações. Por exemplo, se o jogador A solicitar ajuda externa e o jogador B disser "Eu tenho um duque e bloqueio sua ajuda externa", A poderá dizer "Não acredito que você tenha um duque". Se essa afirmação estiver correta, B perde uma carta por ter sido pego em uma mentira e A recebe 2 moedas; caso contrário, A perde uma carta e não recebe moedas, e B deve devolver seu duque ao baralho e comprar uma nova carta.
A maneira como os blocos e os desafios funcionam com o Assassinate deve ser aprimorada. Suponha que o Jogador A diga "Eu tenho um Assassino e Eu Assassino o Jogador B". Se B não tentar desafiar ou bloquear A, o assassinato continua: B perde uma carta e A paga 3 moedas.
Como alternativa, B pode contestar dizendo "Eu não acredito que você tenha um assassino". Se isso for verdade, então A descarta uma carta e suas moedas são devolvidas, enquanto B não é afetado e o turn de A termina. Se a crença de B estiver incorreta e A tiver um Assassino, B perde as cartas e falha, uma pelo desafio incorreto e outra pelo Assassinato.
Em vez de desafiar, B poderia dizer "Eu tenho uma condessa e bloqueio o assassino". Se A acredita em B, o turn de A termina e suas moedas não são devolvidas. Mas A pode desafiar o bloco e dizer "Eu não acredito que você tenha uma condessa". Se B de fato segura uma Condessa, então A perde uma carta pelo desafio incorreto. Mas se B não, então B perde uma carta por ter sido pega em uma mentira e outra do Assassinato.
Lógica semelhante à explicação acima se aplica à habilidade Roubo do Capitão, onde a ação ou o bloqueio podem ser desafiados.
É possível perder as duas cartas e ser eliminado em um turno, se você desafiar um Assassino sem sucesso ou for pego falsamente alegando que tem uma Condessa para bloquear um Assassinato. Você perde uma carta do desafio e uma carta do Assassinato.
Desafio
Sua tarefa é escrever um programa que jogará Coup. Será fornecido como seus argumentos de linha de comando:
- O nome de um arquivo que contém a lista de suas ações e de seus oponentes até o momento.
- Um número inteiro de 0 a 12, indicando a contagem de moedas do oponente.
- Um número inteiro de 0 a 12, indicando sua contagem de moedas.
- Uma cadeia de caracteres de um a quatro caracteres, indicando seus cartões. Normalmente, esses serão apenas os um ou dois cartões que seu programa possui, mas se o seu programa tiver sido bem-sucedido em um Exchange, ele terá n + 2 caracteres, onde n é o número de cartões restantes. Seu programa deve enviar os n cartões que deseja manter para STDOUT. (Os programas não devem ler ou acessar STDOUT, exceto para esse fim - se você deseja produzir uma saída de depuração, escreva para STDERR.)
- Um ou mais argumentos indicando os movimentos legais que ele pode fazer.
(Exemplo de invocação:, yourprogram file.txt 1 7 '~!' a c p q
significando "Seu oponente tem 1 moeda. Você tem 7 moedas, um Embaixador e uma Condessa. Escreva em file.txt sua escolha de a, c, p ou q, considerando o histórico do jogo e o estado atual do jogo. ")
Seu programa deve anexar um ou (em duas situações específicas) dois caracteres ao arquivo fornecido, indicando sua ação. Caso contrário, não deve alterar o conteúdo existente do arquivo. Pode criar quaisquer novos arquivos que desejar, mas apenas dentro do diretório em que é executado. Forneça todos os comandos necessários para compilar e executar seu programa.
Forneci dois exemplos de concorrentes abaixo, escritos em Go.
O formato de saída é:
I\n
: Renda. Respostas legais: qualquer ação por turno (supondo que alguém tenha as moedas para Assassinate / Coup).F
: Ajuda externa. Respostas legais:d
(bloqueie como um duque),p
(deixe passar).C
: Golpe. As respostas legais: qualquer que seja o de_
,'
,<
,=
,0
está na sua mão.E
: Troca. Respostas legais:q
(desafio, não acreditando que o jogador tenha um embaixador)p
,.T
: Imposto. Respostas legais:q
(desafio, não acreditando que o jogador tenha um duque)p
,.A
: Assassinado. As respostas legais:s
(bloco como um Contessa),q
(desafio), e qualquer que seja o de_
,'
,<
,=
,0
está na sua mão.S
: Roubar. Respostas legais:a
(bloco como embaixador),c
(bloco como capitão),q
(desafio, não acreditando que o jogador tenha um capitão)p
,.d
: bloquear a ajuda externa como duque. Respostas legais:\n
(aceite o bloqueio),q
(desafio, não acreditando que o jogador tenha um duque).a
: bloquear um roubo como um embaixador. Respostas legais:\n
(aceite o bloqueio),q
(desafio, não acreditando que o jogador tenha um embaixador).c
: bloquear um roubo como um capitão.\n
(aceita o bloqueio),q
(desafio, não acreditando que o jogador tenha um capitão).s
: bloquear um assassino como uma condessa. Respostas legais:\n
(aceite o bloqueio),q
(desafio, não acreditando que o jogador tenha uma Condessa).p
: passe desafiando uma troca / imposto / roubo quando não for a sua vez. Não usado comA
; se recusar a desafiar um Assassinato, escreva um deles_'<=0
. Resposta legal:\n
(finalize seu turno) e, se você acabou de obter sucesso no Exchange, escreva as cartas que deseja manter do quarto argumento da linha de comando em STDOUT.q
: desafie a ação ou bloco mais recente. Resposta legal: se você tiver o cartão da ação que foi contestada, qualquer~^*!$
que seja. Caso contrário, qualquer que seja da_'<=0
sua mão que você deseja desistir, seguido de uma nova linha se e somente se for a sua vez.~
,^
,*
,!
,$
: Revelar que esteve dizendo a verdade sobre a realização, respectivamente, um embaixador, um assassino, um capitão, um Contessa, e Duke (também usado para representar estes cartões em argumentos de linha de comando e STDOUT de saída em um Exchange ) As respostas legais: qualquer que seja o de_
,'
,<
,=
,0
você tem em sua mão._
,'
,<
,=
,0
: Dar-se como castigo, respectivamente, um embaixador, e assassino, um capitão, um Contessa, e Duke, porque você perdeu um desafio ou foram assassinados / couped. Resposta legal:\n
.\n
: encerre seu turno, recusando-se a desafiar um bloco, se aplicável. Respostas legais: qualquer ação com letras maiúsculas (supondo que alguém tenha as moedas para Assassinate / Coup e o oponente tenha as moedas para roubar).
O formato possui as seguintes propriedades úteis:
- As voltas começam com uma letra maiúscula.
- As linhas seguem o padrão: letra maiúscula, minúscula, opcionalmente sinais de pontuação ou 0 para cartões revelados, nova linha.
- Um arquivo que termina com uma nova linha ou um arquivo vazio indica que é o início da vez do seu programa e deve escolher uma ação de letras maiúsculas.
- As ações legais que você tem permissão para executar uma invocação geralmente são determinadas exclusivamente pelo último caractere no arquivo. A exceção é
q
, que terá alguma lógica associada a ela. Veja a funçãoget_legal_actions
no árbitro para ajudar a entender isso. Ou você pode simplesmente usar as ações legais recebidas na linha de comando. - Um número par de caracteres em uma linha indica que o turno é seu e seu programa é convidado a escolher uma ação, desafiar um bloco ou encerrar seu turno.
- Um número ímpar de caracteres em uma linha indica que o turno não é seu e seu programa é solicitado a bloquear, desafiar ou revelar / entregar uma carta.
Vou dar um exemplo para cada ação.
I\n
é o mais fácil de entender. Um programa pega uma moeda de Renda e termina seu turno. Este é um dos dois casos em que os programas devem imprimir dois caracteres, pois Renda é a única ação em que o oponente não é afetado e não pode bloquear ou desafiar.
Fp\n
significa que um programa recebeu ajuda externa e seu oponente se recusou a bloquear ( p
). Em sua próxima chamada, o primeiro programa observou que, pela última letra minúscula p
e / ou pelo número par de caracteres nessa linha, essa curva foi executada, que ainda não terminou, portanto, ela sabe encerrar sua curva atual imprimindo uma nova linha.
C=\n
significa que um programa lançou um golpe. Seu oponente, sabendo que foi chamado a reagir pelo número ímpar de letras na linha, desistiu de uma Condessa. Novamente, o primeiro programa sabia que essa era a sua vez incompleta em sua próxima invocação pelo número par de caracteres na linha; portanto, ele escreveu uma nova linha para encerrar sua vez.
Eq~<\n
significaria que um programa tentou um Exchange ( E
) e seu oponente desafiou ( q
). O programa de Intercâmbio revelou que realmente tinha um Embaixador ( ~
) e o desafiante desistia de um Capitão como punição ( <
). Depois que o desafiante sai, o programa de Troca é chamado novamente com uma cadeia de quatro caracteres como seu quarto argumento de linha de comando (ou três caracteres, se tiver apenas um cartão). Ele grava os caracteres que representam os cartões que deseja manter em STDOUT e uma nova linha no arquivo.
Tq'\n
significa que um programa tentou um imposto falso, foi contestado e desistiu de um assassino. Ilustra o outro caso em que dois personagens são escritos: se é a sua vez e você é forçado a desistir de uma carta - seja pelo desafio correto de um oponente (como aqui) ou pelo desafio incorreto de um bloco -, você deve escrever ambos a carta que você desiste e uma nova linha para terminar o seu turno.
Asq!'\n
significaria que o jogador B tentou assassinar o jogador A ( A
), mas A alegou ter uma Condessa para bloqueá-lo ( s
). B não acreditou em A e desafiou ( q
). A revelou que eles tinham, de fato, uma Condessa ( !
). B desistiu de um Assassino como punição, perdendo suas moedas e terminou seu turno ( '\n
), escrevendo dois caracteres como naquele caso especial. (Se A tivesse decidido não bloquear ou desafiar, poderia ter escrito =
, e então seu oponente teria visto que o turn havia terminado e escrito uma nova linha. A linha teria lido A=\n
, como no exemplo do golpe.)
Sq*0\n
significa que um programa tenta roubar; o oponente desafia, não acreditando que o ladrão tenha um capitão; e o programa original revela um capitão, então o desafio não é bem-sucedido e o desafiante desiste de um duque como punição. (Outra opção para o oponente seria aceitar o roubo roubando p
. O oponente detectaria o final do turno e escreveria \n
, resultando em uma linha de Sp\n
.)
O árbitro
Os programas serão chamados por esse script Python. Realiza dez rodadas, nas quais todos os competidores enfrentam todos os outros competidores, indo primeiro e segundo. Ele rastreia cartões e contagens de moedas e determina o perdedor pelo primeiro programa para terminar uma linha com um sinal de pontuação duas vezes. Programas que saem com um status diferente de zero, modificam o arquivo, gravam uma movimentação ilegal no arquivo ou tentam um Exchange ilegal perderá automaticamente. Se cada jogador realizar mais de 100 ações, incluindo blocos e desafios, sem vencedor, os dois programas perderão. Um vencedor recebe um ponto. O jogador cujo programa obtiver mais pontos ganha.
Eu sugiro que você leia o código fonte do árbitro, especialmente a get_legal_actions
função. Isso pode ajudá-lo a entender a especificação e escrever seus próprios programas.
import itertools
import os
import random
import subprocess
class Player:
def __init__(self, name, command):
self.name = name
self.command = command
self.score = 0
self.coins = 1
self.cards = ""
actions_dict = {
'E': '_', 'T': '0', 'A': "'", 'S': '<',
'd': '0', 'a': '_', 'c': '<', 's': '='
}
punishment_to_reveal = {'_': '~', "'": '^', '<': '*', '=': '!', '0': '$'}
reveal_to_punishment = {
punishment_to_reveal[k]: k for k in punishment_to_reveal
}
def get_legal_actions(history, player, opponent):
c = history[-1]
result = ""
# Our turn begins; choose an action.
if c == '\n':
if player.coins >= 10:
return ["C"]
ret = ['I\n'] + list("FET")
if player.coins >= 3:
ret.append("A")
if player.coins >= 7:
ret.append('C')
if opponent.coins > 0:
ret.append("S")
return ret
# Opponent attempted foreign aid; can pass or claim Duke to block.
elif c == 'F':
return list('dp')
# We have been Couped; must surrender a card.
elif c == 'C':
return player.cards
# We failed a challenge; must surrender a card and print a newline
# if it is our turn.
elif c in '~^*!$':
if history[-3] in 'acds':
return [card + '\n' for card in player.cards]
return player.cards
# Opponent attempted Exchange or Tax; can pass or challenge.
elif c == 'E' or c == 'T':
return list('pq')
# Opponent attempted an Assassination; can block, challenge, or give in.
elif c == 'A':
return list('sq') + player.cards
# Opponent attempted to Steal; can pass, block as Ambassador/Captain,
# or challenge.
elif c == 'S':
return list('acpq')
# Opponent blocked; can challenge or withdraw.
elif c in 'acds':
return list('q\n')
# Opponent passed on blocking Foreign Aid/Tax/Exchange or they gave up a
# card as punishment, must end turn.
elif c in "p_'<=0":
return ['\n']
# Opponent challenged us.
elif c == 'q':
challenged_action = history[-2]
# If we have the card they challenged us over, must reveal it.
necessary_card = actions_dict[challenged_action]
if necessary_card in player.cards:
return [punishment_to_reveal[necessary_card]]
# Otherwise, we can give up either of our cards, writing a newline
# if it is our turn.
if challenged_action in 'acds':
return list(player.cards)
else:
return [card + '\n' for card in player.cards]
else:
return None
deck = ['_', "'", '<', '=', '0'] * 3
random.shuffle(deck)
def determine_turn_effects(line, output, cards, current_player, opponent):
last_action = line[-2]
# Only operate if the opponent declined to challenge (p) or the
# program successfully challenged their block
if last_action in "p_'<=0":
primary_action = line[0]
# Foreign Aid
if primary_action == 'F':
print current_player.name, "received 2 coins of Foreign Aid"
current_player.coins += 2
# Tax
elif primary_action == 'T':
print current_player.name, "received 3 coins of Tax"
current_player.coins += 3
# Steal
elif primary_action == 'S':
stolen_coins = 1 if opponent.coins == 1 else 2
print current_player.name,\
"stole %d coins from %s" % (stolen_coins, opponent.name)
current_player.coins += stolen_coins
opponent.coins -= stolen_coins
# Exchange, store desired cards and replace undesired ones
elif primary_action == 'E':
print current_player.name, "tried to take %r" % output, "from", cards
legal_outputs = [''.join(p) for p in itertools.permutations(
cards, len(current_player.cards))]
if output not in legal_outputs:
print current_player.name, "forfeits by illegal exchange"
return opponent
current_player.cards = [
reveal_to_punishment[c] for c in output
]
undesired_cards = list(cards)
for c in output:
undesired_cards.remove(c)
for card in undesired_cards:
deck.append(reveal_to_punishment[card])
random.shuffle(deck)
# Coins are not returned from a successful Contessa block
elif last_action == 's':
print current_player.name, "lost 3 coins from a Contessa block"
current_player.coins -= 3
return None
def play_game(player1, player2, round_number, game_number):
outfilename = os.path.abspath(__file__)[:-len(__file__)] + '_'.join([
player1.name, player2.name, str(round_number), str(game_number)
]) + '.txt'
print outfilename
f = open(outfilename, 'w')
f.close()
players_list = [player1, player2]
player1.cards = [deck.pop(), deck.pop()]
player2.cards = [deck.pop(), deck.pop()]
current_player_index = 0
for i in range(200):
current_player = players_list[current_player_index]
opponent = players_list[(current_player_index+1) % 2]
legal_actions = []
original_contents = []
original_contents_joined = ""
with open(outfilename, 'r') as outfile:
original_contents = outfile.readlines()
original_contents_joined = ''.join(original_contents)
if len(original_contents) == 0:
legal_actions = ['I\n'] + list("FEST")
else:
legal_actions = get_legal_actions(
original_contents[-1], current_player, opponent)
if not legal_actions:
print "Error: file ended in invalid character"
return current_player
# Has the player completed an Exchange? Pass them new cards if so.
exchange_cards = ""
old_last_line = original_contents[-1] if len(original_contents) > 0 else '\n'
if old_last_line[-1] != '\n' and old_last_line[0] == 'E' and \
len(old_last_line) % 2 == 0 and old_last_line[-1] in "p_'<=0":
exchange_cards = punishment_to_reveal[deck.pop()] + \
punishment_to_reveal[deck.pop()]
cards = exchange_cards + ''.join(
punishment_to_reveal[card] for card in current_player.cards)
args = current_player.command + [
outfilename,
str(opponent.coins),
str(current_player.coins),
cards
] + legal_actions
print ' '.join(args)
output = ""
os.chdir(current_player.name)
try:
output = subprocess.check_output(args)
# Competitors that fail to execute must forfeit
except subprocess.CalledProcessError:
print current_player.name, "forfeits by non-zero exit status"
return opponent
finally:
os.chdir('..')
new_contents = []
new_contents_joined = ""
with open(outfilename, 'r') as outfile:
new_contents = outfile.readlines()
new_contents_joined = ''.join(new_contents)
if original_contents_joined != new_contents_joined[:-2] and \
original_contents_joined != new_contents_joined[:-1]:
print current_player.name, "forfeits by modifying the file"
print "old:", original_contents
print "new:", new_contents
return opponent
new_last_line = new_contents[-1]
the_move_made = ""
for action in legal_actions:
if new_last_line.endswith(action):
the_move_made = action
break
# Competitors that make an illegal move must forfeit
if not the_move_made:
print current_player.name, "forfeits with an illegal move,",\
"last line: %r" % new_last_line
print opponent.name, "wins!"
return opponent
print current_player.name, "played %r" % the_move_made
# Side effects of moves.
#
# Income, give the current player a coin.
if the_move_made == "I\n":
print current_player.name, "received 1 coin of income"
current_player.coins += 1
# The program surrendered a card on its turn; take it away.
elif len(the_move_made) == 2:
print current_player.name, "lost a card from being challenged"
current_player.cards.remove(the_move_made[0])
# Coins are not returned from a successful Contessa block
if new_last_line[-3] == '!':
print current_player.name, "lost 3 coins from a Contessa block"
current_player.coins -= 3
# The program surrendered a card when it was not its turn.
elif the_move_made in "_'<=0":
print current_player.name, "gave up a", the_move_made
current_player.cards.remove(the_move_made)
if new_last_line[0] == 'C':
opponent.coins -= 7
elif new_last_line[0] == 'A':
opponent.coins -= 3
# Did the program unsuccessfully challenge an Assassination
# (e.g. Aq^0\n)
# or get caught falsely blocking with a Contessa
# (e.g. Asq0\n)?
# If yes, it loses right away.
if new_last_line[0] == 'A' and new_last_line[1] in 'qs' and \
len(new_last_line) == 4:
print current_player.name, "lost both cards in the same turn."
print opponent.name, "wins!"
return opponent
elif the_move_made == 'S':
print current_player.name, "attempted Steal"
elif the_move_made == 'T':
print current_player.name, "attempted Tax"
elif the_move_made == 'A':
print current_player.name, "attempted Assassinate"
elif the_move_made == 'C':
print current_player.name, "launched a Coup"
elif the_move_made == 'F':
print current_player.name, "attempted Foreign Aid"
elif the_move_made == 'E':
print current_player.name, "attempted Exchange"
elif the_move_made == 'q':
print current_player.name, "challenged"
elif the_move_made == 'p':
print current_player.name, "passed"
elif the_move_made == 'a':
print current_player.name, "blocked with an Ambassador"
elif the_move_made == 'c':
print current_player.name, "blocked with a Captain"
elif the_move_made == 's':
print current_player.name, "blocked with a Contessa"
elif the_move_made == 'd':
print current_player.name, "blocked with a Duke"
# The program revealed a card from an opponent's unsuccessful challenge.
# Give it a new card.
# Special case: a program whose Exchange is unsuccessfully challenged
# may keep the Ambassador it revealed in the Exchange, so give a new
# card for a revealed Ambassador only if it was used to block a Steal.
elif the_move_made in '^*!$' or (the_move_made == '~' and
new_last_line[0] == 'S'):
p = reveal_to_punishment[the_move_made]
current_player.cards.remove(p)
current_player.cards.append(deck.pop())
deck.append(p)
random.shuffle(deck)
print current_player.name, "did have a", the_move_made
# The program ended its turn. We must examine the rest of the line to
# determine the side effects.
elif the_move_made == '\n':
potential_winner = determine_turn_effects(
new_last_line, output.strip(), cards, current_player,
opponent)
if potential_winner:
print potential_winner.name,\
"wins because their opponent made an illegal exchange!"
return potential_winner
# One player has lost all their cards. Victory for the opponent!
if current_player.cards == []:
print opponent.name, "wins by eliminating both opponent cards!"
return opponent
current_player_index += 1
current_player_index %= 2
return None
competitors = []
competitors.append(Player("Challenger", ["./challenger"]))
competitors.append(Player("Random", ["./random"]))
# ...More competitors here
for i in range(10):
print "-- Round", i
j = 0
for pairing in itertools.permutations(competitors, 2):
player1, player2 = pairing
print '--- Game', j, ':', player1.name, 'vs.', player2.name
winner = play_game(player1, player2, i, j)
if not winner:
j += 1
continue
winner.score += 1
player1.coins = 1
player1.cards = ""
player2.coins = 1
player2.cards = ""
deck = ['_', "'", '<', '=', '0'] * 3
random.shuffle(deck)
j += 1
competitors.sort(reverse=True, key=lambda player: player.score)
for player in competitors:
print '%5d %s' % (player.score, player.name)
Diversos
Um programa não pode ter código específico para outro programa e os programas não podem ajudar um ao outro. (Você pode ter vários programas, mas eles não podem interagir de forma alguma.)
Se o seu programa perder as duas cartas no mesmo turno, precisará escrever apenas uma. O árbitro detectará que foi eliminado.
É possível e incentivado, mas não obrigatório, que os programas examinem o histórico do jogo no arquivo. Ao fazer isso, eles podem determinar quais cartas seu oponente afirmou ter e pegá-las em uma mentira.
No jogo real de golpe, você pode desafiar uma ação e depois tentar bloqueá-la no mesmo turno. Eu não poderia fazer a especificação funcionar se permitisse isso; portanto, você pode desafiar ou bloquear uma determinada ação, mas não as duas.
Peço desculpas ao @PeterTaylor, que na época anterior eu postei isso sugerido que eu o publicasse na sandbox e refizesse o protocolo para canalizar a saída de um lado para outro no STDOUT / STDIN. Eu tentei, com tanto esforço, fazer esse trabalho, passando um dia inteiro nele (quando eu já havia passado um dia inteiro escrevendo o desafio original). Mas as trocas se mostraram muito complicadas de implementar dessa maneira, além de aumentar a complexidade dos envios ao exigir que eles monitorem sua própria contagem de moedas. Portanto, publiquei o desafio mais ou menos como era originalmente.
fonte
S
, o programa B bloqueia por escritoc
, A se recusa a contestar escrevendo\n
. Um desafio bem-sucedido de um roubo seria: A escreveS
, B desafia escrevendoq
, A concede o desafio escrevendo_\n
, por exemplo , você pode executar apenas uma ação por turno, incluindo o Exchange. As respostas legais ao Exchange são aprovadas e contestadas.Respostas:
Calculadora
Planeja sua série vencedora de jogadas e desafia qualquer coisa que o impeça de vencer.
Turncoat
Diz a verdade a princípio, mas começa a mentir quando deixa de ser desafiado. Também tem algum comportamento de solucionador. (Uma aproximação de como eu me comporto ao jogar este jogo com humanos)
Bandido
Tenta se livrar dos embaixadores e capitães do oponente e ganha roubando.
Assassinato Sangrento
Uma contraparte do Bandit, essa aposta na estratégia Duke + Assassin.
fonte
Solver
O Solver tenta lembrar quais cartas são jogadas antes e quais foram os movimentos anteriores do oponente.
esta é a segunda versão ainda não concluída (e está uma grande bagunça agora)
para fazê-lo funcionar no nó 10, adicione
competitors.append(Player("Solver", ["node", "--experimental-modules", "./solver.mjs"]))
se o nó 12
competitors.append(Player("Solver", ["node", "./solver.js"]))
tenha cuidado com o tipo de arquivo
fonte
Advogado
O advogado percorre o mundo com cautela, nunca mentindo, bloqueando quando possível, desafiando quando não em seu prejuízo imediato. Ele não ataca, exceto quando exigido pelo golpe, mas recebe moedas o mais rápido possível para obter um golpe rápido. Ele é inteligente o suficiente para sacrificar cartões que não usa primeiro, mas não é inteligente o suficiente para usá-los para se livrar deles e adquirir novos.
Provavelmente existem erros neste programa. Quando você encontrá-los, por favor me avise.
fonte
Aleatória
Random não sabe o que fazer, então ele seleciona aleatoriamente algo legal.
Desafiador
Challenger não confia em ninguém neste jogo de engano. Se você fizer algo desafiador, ele o desafiará. Caso contrário, ele apenas recebe renda a cada turno e tenta golpeá-lo se ele tiver as moedas.
Compile esses programas com
go build random.go/challenger.go
e execute com./random
ou./challenger
.fonte
Taxman
O contribuinte está aqui para cobrar impostos. Usa assassino se eles tiverem um. Bloqueia apenas se eles tiverem o cartão para bloquear. Desafios aleatoriamente.
Escrito em c #, gastei muito tempo construindo uma hierarquia de classes para todas as diferentes ações que podem ser executadas.
Edit: Agora, com lógica aprimorada, como não afirmar ter um duque quando desistiram de um duque depois de serem desafiados. Também não tenta mais assassinar continuamente se o oponente bloqueia com a condessa (e não é desafiado).
fonte
determine_turn_effects()
a ação Steal está pegando todas as moedas do oponente. Deve levar no máximo duas moedas.Advogado Rando Aggro
Semelhante ao advogado, ele só faz coisas legais. No entanto, ele assassina, golpeia mais cedo e escolhe algumas ações aleatoriamente (como quando desafiar).
fonte
mascarar
The Mask é um mestre do disfarce. Ele impede que os oponentes acompanhem suas cartas trocando toda vez que ele age ou bloqueia. Sua estratégia vencedora é receber 3 moedas como Duke e depois Assassinate.
Compilar com
go build mask.go
, executar com./mask
.fonte
Jogador
O jogador tem uma estratégia detalhada, mas confia em seu intestino quando uma situação não é explicada em sua estratégia vencedora. Ele tenta roubar muito e golpes / assassinatos sempre que possível.
Escrito em Python3:
Estatístico
Conhece sua estratégia vencedora, assim como o jogador, mas sempre confia nas probabilidades máximas em vez de fazer amostragens aleatórias a partir delas.
fonte
Traceback (most recent call last): File "gambler.py", line 94, in <module> otherhand = guess_opponents_hand() File "gambler.py", line 61, in guess_opponents_hand card_counts[card_give_up.index(card_1)] -= 1 ValueError: ['_'] is not in list
.\n
vez do cartão que desejam desistir. Em tal situação, é melhor lutar com um bloqueio ou desafio. Se Gambler tivesse vencido os 5 jogos perdidos assim, teria ficado em primeiro lugar.