Resultados finais disponíveis
Introdução
Depois do meu KOTH anterior, com temas pesados ( guerra de fantasia , pandemia mundial ...), estou de volta com um novo jogo leve. Desta vez, você está enfrentando uma situação de "jogo de tabuleiro". Uma pilha de moedas de cabeça para baixo é colocada no centro de uma mesa muito grande e você está determinado a receber sua parte do saque!
Glossário
Moedas : tokens que podem ser invertidos ou invertidos.
Unflipped : Moedas colocadas na mesa com o valor apontando para baixo. Este é o estado padrão das moedas.
Lançado : Moedas colocadas na mesa com o valor apontando para cima.
Local : refere-se à sua pilha de moedas.
Global : refere-se à pilha de moedas no centro.
Princípio
No início do jogo, cada jogador começa com 0 pontos e 0 moedas (lançadas ou não). O jogo é baseado em turnos. Durante o turno, os jogadores podem realizar até 3 ações interagindo com a pilha de moedas no centro da mesa, sua própria pilha de moedas ou com outros jogadores.
A ordem do jogo é definida aleatoriamente no início do jogo. A ordem dos jogadores na lista de argumentos representa a ordem do turno e vai da esquerda para a direita nessa lista. "Próximo" e "Anterior" referem-se, respectivamente, a "à direita nessa lista" e "à esquerda nessa lista" com um loop, se você for o último dos dois lados.
O jogo dura 50 rodadas ou até que haja 0 moedas no centro no final do turno do jogador (o que significa que você terminará suas 3 ações, mesmo que a pilha esteja vazia após a sua primeira ação, e você poderá colocar de volta moedas para deixar o jogo continua). O número inicial de moedas globais é definido aleatoriamente com esta fórmula:
(2 ^ nb_players) + (nb_players * 10) - random(1 + (nb_players ^ 2))`
Cada ação lhe dará pontos (ou fará com que você perca alguns) e, no final do jogo, cada moeda que você tiver será adicionada aos seus pontos ( -1 para não jogado, +2 para jogado ). O jogador com mais pontos ganha.
O controlador fornece entrada por meio de argumentos de comando, e seu programa deve gerar via stdout.
Sintaxe
Entrada
Cada vez que seu programa é chamado, ele recebe argumentos neste formato:
Round;YourPlayerId;Coins;PlayerId_Points_Flipped_Unflipped;PlayerId_Points_Flipped_Unflipped;...
As rodadas são indexadas em 1.
Exemplo de entrada
6;2;52;1_20_3_12;0_-2_0_1;2_12_1_0
Aqui, você vê que é a 6ª rodada e você é o jogador 2. Há 52 moedas na pilha central. Você tem 12 pontos, 1 moeda lançada e 0 moeda não lançada. Os pontos podem ser negativos.
Saída
Você precisa produzir três caracteres (sem espaço, sem separador), cada um correspondendo a uma ação que você executará neste turno. A ordem dos caracteres determina a ordem das ações. Você pode emitir as mesmas ações várias vezes. Caso não haja moedas suficientes para concluir sua ação, ele usará o máximo de moedas disponíveis e contará pontos apenas para as moedas usadas.
N
: Não faça nada
1
: Pegue 1 moeda da pilha central [Efeitos: +1 desbloqueado local / -1 ponto / -1 desbloqueado global]
2
: Pegue 2 moedas da pilha central [Efeitos: +2 desbloqueado local / -2 pontos / -2 desbloqueado global]
3
: pegue 3 moedas da pilha central [Efeitos: +3 desbloqueado local / -3 pontos / -3 desbloqueado global]
A
: coloque 1 moeda da sua pilha [Efeitos: -1 desbloqueado local / +1 ponto / +1 global unflipped]
B
: Coloque de volta 2 moedas da sua pilha [Efeitos: -2 locais não lançados / +2 pontos / +2 global unflipped]
C
: Coloque de volta 3 moedas da sua pilha [Efeitos: -3 locais não lançados / +3 pontos / +3 global unflipped]
X
: remova 1 moeda da sua pilha[Efeitos: -1 local não jogado / 0 ponto]
Y
: Remova 2 moedas da sua pilha [Efeitos: -2 local não jogado / 0 ponto]
Z
: Remova 3 moedas da sua pilha [Efeitos: -3 local não jogado / 0 ponto]
R
: Gire moedas ao jogador anterior [Efeitos: -1 ponto por flipper recebido, +2 pontos por flipped recebido / aplica-se a todos os jogadores]
T
: Gire moedas para o próximo jogador [Efeitos: -1 ponto por flipper recebido, +2 pontos por flipped recebido / aplica-se a todos os jogadores]
F
: Jogue 1 moeda [Efeitos: -1 local invertido / +1 local invertido / +2 pontos]
U
: Solte 1 moeda [Efeitos: +1 local não invertido / -1 local invertido / -2 pontos]
Saída de exemplo
2FF
: Pega duas moedas e vira duas moedas, marcando -2 + 2 + 2 = 2 points
Se sua saída estiver incorreta, o controlador assumirá NNN
.
Controlador
Você pode encontrar o controlador no GitHub . Ele também contém dois samplebots, escritos em Java. Para executá-lo, confira o projeto e abra-o no seu IDE Java. O ponto de entrada no main
método da classe Game
. É necessário o Java 8.
Para adicionar bots, primeiro você precisa da versão compilada para Java (arquivos .class) ou das fontes das linguagens interpretadas. Coloque-os na pasta raiz do projeto. Em seguida, crie uma nova classe Java no players
pacote (você pode dar um exemplo nos bots já existentes). Esta classe deve ser implementada Player
para substituir o método String getCmd()
. A String retornada é o comando do shell para executar seus bots. Você pode, por exemplo, fazer um trabalho de bot rubi com este comando: return "C:\Ruby\bin\ruby.exe MyBot.rb";
. Por fim, adicione o bot na matriz de jogadores na parte superior da Game
classe.
Regras
- Os bots não devem ser escritos para vencer ou suportar outros bots específicos.
- A gravação em arquivos é permitida. Por favor, escreva para "YOURSubmissionname.txt", a pasta será esvaziada antes do início do jogo. Outros recursos externos não são permitidos.
- Seu envio tem 1 segundo para responder.
- Forneça comandos para compilar e executar seus envios.
Idiomas suportados
Vou tentar dar suporte a todos os idiomas, mas ele precisa estar disponível online gratuitamente. Por favor, forneça instruções de instalação se você não estiver usando um idioma "mainstream".
A partir de agora, eu posso executar: Java 6-7-8, PHP, Ruby, Perl, Python 2-3, Lua, R, node.js, Haskell, Kotlin, C ++ 11.
Resultados finais
Estes são os resultados de 100 jogos (soma de pontos):
1. BirdInTheHand: 1017790
2. Balance: 851428
3. SecondBest: 802316
4. Crook: 739080
5. Jim: 723440
6. Flipper: 613290
7. Wheeler: 585516
8. Oracle: 574916
9. SimpleBot: 543665
10. TraderBot: 538160
11. EgoisticalBot: 529567
12. RememberMe: 497513
13. PassiveBot: 494441
14. TheJanitor: 474069
15. GreedyRotation: 447057
16. Devil: 79212
17. Saboteur: 62240
Os resultados individuais dos jogos estão disponíveis aqui: http://pasted.co/63f1e924 (com moedas iniciais e número de rodadas por jogo).
Uma recompensa de 50 reputações é concedida ao vencedor: Bird In The Hand, de Martin Büttner .
Obrigado a todos por sua participação, até a próxima KOTH ~
fonte
Respostas:
Pássaro na mão, Ruby
Se nenhum de nós tem um bug em seus programas, o principal algoritmo disso é provavelmente muito semelhante ao Oracle de Mathias. Com base no pressuposto de que, antes da rodada final, não podemos saber com quais moedas terminaremos, avaliamos o conjunto de movimentos atual puramente com base nos pontos recebidos imediatamente, ignorando completamente que tipo de moeda acabaremos com. Como existem apenas 14 3 = 2744 conjuntos de movimentos possíveis, podemos simular facilmente todos eles para descobrir quantos pontos eles trarão.
No entanto, se um conjunto de jogadas terminar o jogo (seja porque reduz o pote global a zero, ou porque esta é a rodada 50 e somos os últimos a se mover), também levará em consideração as moedas pertencentes ao final de o conjunto de movimentos para determinar o valor do conjunto de movimentos. Eu considerei terminar o jogo sempre que possível, mas isso resultaria em uma jogada horrível
333
quando restassem apenas 9 moedas no pote.Se houver vários conjuntos de movimentos que dão o mesmo resultado, escolhemos um aleatório. (Eu posso mudar isso para enviesá-lo em favor dos conjuntos de movimentos que terminam o jogo.)
fonte
Oracle, Python 3
Atualização: mudou a ordem das várias tentativas para favorecer a baixa pilha de moedas sobre as rotações.
Tenta cada saída possível e mantém a que produz a quantidade máxima de pontos para este turno.
fonte
deepcopy
complexidade do espaço (portanto, do tempo [ ]) mantendo apenas vizinhos relevantes. Não tenho certeza de como isso afetará as coisas.filter_neighbors
e modifiqueiinvalid_move
para esclarecer a questão. Porém, não consigo reproduzir o erro:$ python oracle.py '4;7;2040;8_-28_1_10;9_-43_0_9;2_-10_4_3;6_-24_6_3;0_6_2_12;1_48_3_0;10_21_4_8;5_6_5_1;4_-12_3_7;7_10_1_3;3_1_1_0'
printsTTR
Rotação gananciosa, Ruby
Isso é bastante semelhante à abordagem do ArtOfCode, exceto que isso verifica de qual vizinho podemos obter mais pontos e escolhe em
C
vez deF
terminar com 3 ou mais moedas após a rotação.Depois de escrever isso, tenho certeza de que uma abordagem melhor seria apenas escolher com avidez o melhor de todos os movimentos todas as vezes, precedendo a rotação tomando, se possível (em vez de usar um fixo "desmonte, gire, se livre) padrão "invertido").
Isso também não leva em conta os pontos implícitos representados pelas moedas realmente possuídas (com base no pressuposto de que o jogo vai durar rodadas suficientes para que eu provavelmente não acabe mantendo minhas moedas de qualquer maneira).
fonte
Flipper, Python 2
Flipper recolhe moedas e tenta girar de um lado para o outro. Flipper não é um jogador inteligente, mas tenta ser uma força positiva no jogo.
Flipper só precisa
python flipper.py <arg>
correr.fonte
SimpleBot, Python 3
SimpleBot é, bem, simples. Ele elaborou uma estratégia e vai continuar com ela.
Para correr:
onde o conteúdo do
main.py
arquivo é:fonte
Balance, Lua
O Balance tentará manter o equilíbrio em seu símbolo, minimizando a perda no caso de alguém usar as ações
R
eT
contra ele. Ele acha que esse estilo de vida é o verdadeiro e deve ser aplicado a qualquer um que não mantenha um bom equilíbrio de moedas lançadas / não lançadas, para que todos os que estão próximos a ele sejam punidos assim que isso os faça perder pontos.Ele precisa do seguinte comando para executar:
Onde o arquivo balance.lua contém o seguinte trecho de código:
fonte
O zelador, Python 3
Ele tenta limpar a bagunça que os outros jogadores fazem com todas essas moedas e colocá-las de volta na piscina.
Ele tenta devolver todas as suas moedas que não foram lançadas, se ele tiver algumas moedas lançadas e presas, ele será retirado e se ele se livrar de todas as suas moedas, ele receberá outra pessoa.
fonte
Crook, R
Para correr:
Rscript Crook.R
Basicamente, ele troca suas moedas com seus vizinhos apenas se a troca for desigual a seu favor. Se não for possível uma troca benéfica, ela troca moedas com a pilha global de uma maneira que mantém sua relação intacta, mas gera alguns pontos.
Edit: Eu adicionei um pouco de profundidade a este bot, fazendo com que ele verifique as pilhas de 2 e 3 jogadores seguintes e anteriores, em vez de apenas a seguinte, e verifique se, no geral, é benéfico girar tantas vezes.
2º Edit : Seguindo a idéia de @ MartinBüttner, o bot agora executa um "RT", ou "TR", se seria mais benéfico para ele do que para seus vizinhos (se eu não errasse ao implementá-lo :)).
fonte
RTR
lo para que você obtenha a pontuação das moedas duas vezes.Jim, Ruby
baseado na rotação gananciosa de Martin Büttner .
irá rodar de uma maneira ou de outra, dependendo do que lhe dará mais pontos em comparação com o melhor outro jogador. Então, ele vira dinheiro rápido.
fonte
TraderBot
Esse bot tenta girar sempre que é o que leva mais pontos nessa ação. Se ele não puder girar, tente se livrar das moedas não lançadas ou demorar um pouco mais para alterá-las nas ações a seguir.
importar java.util.List;
classe pública TraderBot {
Para executar: basta adicioná-lo à mesma pasta que os bots padrão e depois criar a seguinte classe
Em seguida, adicione essa classe à
Player[] players
matriz.fonte
Wheeler
Wheeler calculou a melhor jogada possível ao girar as moedas.
fonte
Sabotador, Python 2
A aleatoriedade significa que provavelmente não sabotará muito bem, mas depois acho que vou esperar até o 'fim' (quantas voltas / moedas restam) e ENTÃO girar, depois de olhar para os jogadores acessíveis nas proximidades para roubar. ... na verdade, apenas fazer uma rotação parece muito ruim, considerando que outras pessoas também podem usar rotações. Eu não acho que isso funcionará muito bem ...
fonte
SecondBest, Python 3
Este programa analisará todas as três combinações possíveis de movimentos e escolherá a segunda melhor.
Porque se você tem a jogada perfeita, provavelmente é uma armadilha.
Editar: entrada comentada removida
Editar: o código estava imprimindo uma jogada legal aleatória. Agora deve estar retornando o segundo melhor resultado.
fonte
Bot do Diabo
Embora sua produção seja apenas metade do número do diabo, os resultados devem ser bastante desastrosos. Tomando 9 moedas a cada turno, acaba esgotando a pilha de moedas. Como esse bot nunca joga nenhuma das moedas necessárias, é extremamente ruim para quem estiver sentado ao lado dele quando houver uma rotação (-9 pontos por cada turno realizado por esse bot).
Comando:
python3 devil.py
Espero fazer alguns robôs reais mais tarde.
fonte
Lembre-se de mim, Python 3
Este programa contém uma quantidade significativa de dados embutidos de um teste contra o bot SecondBest fixo.
Ele deve aprender quais movimentos são os melhores para usar, mas não usa as informações de outros jogadores.
Editar: removido cálculo de ponto desnecessário
Editar: entrada não comentada do jogador
fonte