Morra, o nobre jogo dos reis

28

fundo

O jogo de Morra é um jogo simples. Na versão "original", vários jogadores jogam simultaneamente um número 0-5 com as mãos, enquanto adivinha a soma total das mãos de todos. A versão que vou usar aqui foi modificada para aumentar o potencial de estratégia não trivial e está descrita abaixo:

  • Existem dois jogadores.
  • Como na pedra-papel-tesoura, os jogadores se movem simultaneamente.
  • A cada turno, cada jogador escolhe um número de 0-5 e também adivinha a escolha de 0-5 de seus oponentes. Isso significa que dois números são emitidos a cada turno. Para esclarecer, a saída de ambos os números deve estar no intervalo de 0 a 5, inclusive.
  • Se você adivinhar a escolha do seu oponente corretamente, mas seu oponente não adivinhou corretamente, você ganha um certo número de pontos igual à soma dos dois números jogados. Por exemplo, se os números jogados fossem 3 e 5, um palpite correto valeria 8 pontos.
  • Se ambos ou nenhum dos jogadores acertarem, nenhum ponto será concedido.
  • A pessoa com mais pontos após 1000 rodadas vence o jogo.

O torneio

O torneio será realizado no estilo round-robin e será realizado com a criação de cada possível par de participantes. Para cada vitória, o competidor ganha 2 pontos de vitória. Cada empate resulta em 1 ponto de vitória. Nenhum ponto de vitória é ganho por uma perda.

Intuitivamente, o vencedor do torneio será o competidor com mais pontos de vitória contra os outros.


Como entrar

Haverá dois métodos para enviar bots para competir. O primeiro, e muito preferido método, é implementar uma interface Java fornecida pelo controlador. O segundo método é escrever um programa independente.

Vamos abordar o método Java primeiro. A interface que você precisará implementar é Playere define dois métodos: public String getName()identifica seu bot e public int[] getMove(String[] args)usa argscomo uma matriz de seis strings mychoices myguesses myscore opponentchoices opponentguesses opponentscore. Um exemplo é o seguinte:

042 045 0 324 432 6

Isso significa que eu escolhi 0 no primeiro turno e adivinhei que meu oponente jogaria um 0. Meu oponente jogou um 3 e adivinhou que eu jogaria um 4. Na terceira rodada, meu oponente fez o palpite correto de que eu jogaria a 2, o que significa que ele ganha 2 + 4 = 6 pontos.

Seu método retornará uma matriz de dois números inteiros, que são sua escolha e suposição, respectivamente. Um exemplo é {4,2}para uma escolha de 4 e um palpite de 2.

Aqui está um exemplo de um bot Java completo escrito como um método. Se você quiser, seu envio deve incluir apenas o que está acontecendo no getMovemétodo.

import java.util.Random;
/**
 * A simple example Morra bot to get you started.
 */
public class ExampleBot implements Player
{
    public String getName()
    {
        return "ExampleBot";
    }

    public int[] getMove(String [] args)
    {
        //easiest way I know to break down to create a move history
        //(just contains their throw history)
        char[] theirThrowsC = args[3].toCharArray();
        int[] theirThrows = new int[theirThrowsC.length];
        for(int i = 0; i < theirThrowsC.length; i++)
        {
            theirThrows[i] = Integer.parseInt(Character.toString(theirThrowsC[i]));
        }

        //get my score
        int myScore = Integer.parseInt(args[2]);

        Random r = new Random();
        int guess = r.nextInt(6);
        if(theirThrows.length > 0)
        {
            guess = theirThrows[theirThrows.length-1];
        }

        //throws a random number, guesses what they threw last
        return new int[] {r.nextInt(6),guess}; 
    }

    public static int otherMethod(int example) //you can write additional static methods
    {
        return 0;
    }
}

Como um programa independente

Atualmente, estou limitado no meu suporte a idiomas adicionais. Além do Java, posso aceitar programas escritos em Python 3.4, Perl 5 ou Ruby 2.1.5. Se houver um idioma que várias pessoas parecem querer, farei o possível para adicioná-lo.

A entrada para o seu programa serão argumentos na linha de comando. Pode ficar assim:

perl awesomebot.plx 042 045 0 324 432 6

A saída do seu programa deve ser a sua escolha, seguida pelo seu palpite, cada um seguido pelo espaço em branco.

Inclua na sua resposta o comando exato necessário para executá-lo. Lembre-se de que estou executando o Windows 8.1.


Regras Extra

Salvando estado e tempos limite

Seu programa poderá criar um arquivo de texto no diretório local, onde você pode armazenar informações. Esta informação será mantida durante todo o torneio, mas excluída posteriormente. Dê ao arquivo um nome que eu possa identificar.

Há um limite de tempo de 500 milissegundos para o seu código responder. A falta de resposta no prazo (ou a movimentação inválida) resultará na perda dessa partida em particular. Os envios de Java atualmente têm um tempo limite passivo (que eu posso atualizar para ativo), enquanto os envios que não são de Java têm um tempo limite ativo em que seu processo é encerrado após 500 milissegundos.

Mais regras de envio

  • Você pode enviar vários envios, desde que respeitem as regras e não participem da equipe de tags.
  • Cada entrada deve ser exclusiva. Você não pode fazer uma cópia exata da lógica de outro bot em um idioma diferente.
  • Os bots não podem interagir entre si (para formar uma equipe de qualquer tipo).
  • Você não pode usar a lógica dos outros bots dentro do seu bot para, por exemplo, identificar seu concorrente e prever suas ações. Você pode, é claro, tentar determinar a estratégia do seu oponente.
  • Não tente mexer com o controlador, outros concorrentes ou meu computador. Não conecte a fontes de informação externas.

O controlador

A versão atual do controlador é encontrada aqui . Está escrito em Java 8. O arquivo "Tournament" é o controlador principal, que também contém a lista de concorrentes (se você deseja hospedar suas próprias competições).


Entre os melhores

Não tenho conseguido atualizar a tabela de classificação com muita frequência. Estou bastante ocupado neste fim de semana. Por "bastante ocupado", quero dizer que não há acesso a um computador das 6:30 às 21:30. Aqui estão as pontuações após 5 corridas. O bot "Echo" continuou perdendo por algum motivo (pode ser minha culpa, ainda não investiguei).

  170 - Quinn and Valor                         
  158 - Historian                               
  142 - DeltaMax                                
  140 - MorraCowbell                            
  132 - Extrapolator                            
  115 - Rainbolt                                
  102 - Popularity                              
  100 - Interpolator                            
   83 - CounterBot                              
   80 - Basilisk                                
   76 - Erratica                                
   65 - Trendy                                  
   63 - Scholar                                 
   62 - RandomGuesser                           
   60 - KingFisher                              
   59 - NullifierBot                            
   55 - EvolvedBot                              
   48 - Confused          

Crédito

Muito obrigado a Rainbolt e Peter Taylor por sua ajuda com o controlador.

PhiNotPi
fonte
1
@ MartinBüttner Ruby 2.1.5 foi adicionado.
PhiNotPi
Como funciona o round robin? Player1 vs Player2 1000 vezes, Player1 vs Player3 1000 vezes etc ... OU é Player1 vs Player2 uma vez, em seguida player1 vs player 3 uma vez, etc ...
Vajura
@Vajura Um único torneio é composto por 1 batalha entre cada par. Uma batalha tem 1000 rodadas, com a maior pontuação total no final da batalha, determinando quem recebe os dois pontos de vitória. O placar atual mostra o total de pontos de vitória após 40 torneios.
PhiNotPi
Desculpe pelos atrasos na atualização do fórum. Estou extremamente ocupado neste fim de semana. Espere e atualize hoje à noite e amanhã de manhã.
PhiNotPi
Uau, eu não esperava que meu bot se saísse tão bem! Além disso, o que os números significam com o primeiro conjunto de resultados ... número de vitórias?
Mbomb007

Respostas:

17

Morra Cowbell

Para quem procura significado no nome desse bot, o nome Morra me faz pensar no espaço italiano , então achei que precisava de um nome que tocasse nisso. Outros candidatos incluíram Morra enganar você e Morra por mim .

Esta é uma classe completa implementando a Playerinterface. Explicação abaixo.

import java.util.Random;

public class MorraCowbell implements Player {
    private final Random rnd = new Random();

    public String getName() {
        return "MorraCowbell";
    }

    public int[] getMove(String[] args) {
        int[] prior = new int[36];
        for (int i = 0; i < 36; i++) prior[i] = 1;
        // args: myChoices myGuesses myScore opponentChoices opponentGuesses opponentScore
        if (args.length == 6 && args[3].length() == args[4].length()) {
            for (int i = 0; i < args[3].length(); i++) prior[6*(args[3].charAt(i) - '0') + (args[4].charAt(i) - '0')]++;
        }

        int[] weights = new int[6];
        for (int r = 0; r < 6; r++) {
            for (int s = 0; s < 6; s++) {
                for (int t = 0; t < 6; t++) {
                    weights[r] += (r + s) * ((r + s == 5 ? 1 : 0) + (r == t ? -1 : 0)) * prior[s * 6 + t];
                }
            }
        }

        // Find the best window.
        int[][] magic = new int[][] {
            { 7776, 6480, 5400, 4500, 3750, 3125 }, { 3125, 2500, 2000, 1600, 1280, 1024 }, { 1875, 1500, 1200, 960,
            768, 640 }, { 1125, 900, 720, 576, 480, 400 }, { 1620, 1296, 1080, 900, 750, 625 }, { 1296, 1080, 900, 750,
            625, 500 }, { 750, 625, 500, 400, 320, 256 }, { 675, 540, 432, 360, 300, 250 }, { 648, 540, 450, 375, 300,
            250 }, { 375, 300, 250, 200, 160, 128 }, { 375, 300, 240, 200, 160, 128 }, { 450, 375, 300, 240, 192, 160,
            128 }, { 324, 270, 225, 180, 150, 125 }, { 270, 225, 180, 144, 120, 100, 80 }, { 225, 180, 150, 120, 96,
            80 }, { 225, 180, 144, 120, 96, 80 }, { 324, 270, 216, 180, 150, 125, 100, 80, 64 }, { 135, 108, 90, 72, 60,
            50 }, { 135, 108, 90, 75, 60, 50, 40, 32 }, { 108, 90, 75, 60, 48, 40, 32 }, { 54, 45, 36, 30, 25, 20, 16 },
            { 54, 45, 36, 30, 24, 20, 16 }
        };
        long bestN = 0;
        int bestD = 1, bestIdx = -1, bestA[] = null;
        for (int[] A : magic) {
            for (int i = 0; i < A.length - 5; i++) {
                long n = 0;
                int d = 0;
                for (int j = 0; j < 6; j++) {
                    n += weights[j] * A[i + j];
                    d += A[i + j];
                }
                if (n * bestD > bestN * d) {
                    bestN = n;
                    bestD = d;
                    bestIdx = i;
                    bestA = A;
                }
            }
        }

        int r = rnd.nextInt(bestD);
        for (int i = 0; i < 6; i++) {
            r -= bestA[bestIdx + i];
            if (r < 0) return new int[] { i, 5 - i };
        }

        // Just a precaution: this should be unreachable.
        return new int[] { 0, 5 };
    }
}

Explicação

Comecei analisando jogos com menos dedos. O mais simples, não trivial, permite fazer chamadas 0ou 1ter a seguinte tabela de pagamentos (os valores são pagos para o jogador de linha):

       (0,0) (0,1) (1,0) (1,1)
      +-----------------------
(0,0) |  0     0    -1     0
(0,1) |  0     0     0     1
(1,0) |  1     0     0    -1
(1,1) |  0    -1     1     0

A (0,0)estratégia é dominada por (0,1), para que possamos reduzir a tabela para

       (0,1) (1,0) (1,1)
      +-----------------
(0,1) |  0     0     1
(1,0) |  0     0    -1
(1,1) | -1     1     0

Agora a (1,0)estratégia é dominada por (0,1), para que possamos reduzir ainda mais a tabela para

       (0,1) (1,1)
      +-----------
(0,1) |  0     1
(1,1) | -1     0

E agora (1,1)é dominado por (0,1), então acabamos com

       (0,1)
      +-----
(0,1) |  0  

Portanto, sempre tocar (0,1)é um equilíbrio de Nash. Mas o curioso é que não é o único. Este é um jogo simétrico de soma zero, portanto o retorno esperado é 0 e qualquer estratégia mista combinada (0,1)e (1,0)onde(0,1) é escolhida pelo menos 50% do tempo alcança esse retorno. Portanto, temos um espaço unidimensional de equilíbrios de Nash.

Parece ser o caso, embora eu não tenha provado isso, que o ndedo Morra tem um npolítopo tridimensional dos equilíbrios de Nash, que são estratégias mistas entre os n+1 (pick, guess)pares para os quais pick + guess = n.

Os números mágicos no código acima codificam os 32 vértices do pólipo 5-dimensional dos equilíbrios de Nash. Eu os encontrei configurando uma instância de programação linear que representava o politopo e, em seguida, usando funções objetivas aleatórias. A razão para codificar todos os 32, em vez de escolher um, é simples: o retorno esperado é 0, então eu preciso me sair melhor do que o esperado para obter uma vitória. Eu suponho essencialmente que o outro jogador esteja usando uma estratégia mista e estime a distribuição com base no histórico de suas escolhas. Depois, seleciono o vértice do polítopo que maximiza meu ganho esperado em relação à distribuição estimada.

QuinnAndValor demonstra a vulnerabilidade da suposição de que o outro jogador está usando uma estratégia mista. Ao detectar um jogador que usa as estratégias dos equilíbrios de Nash, ele pode mudar para um modo de passeio aleatório, onde, jogando uma estratégia de não equilíbrio, é passível de perder, em média, mas só precisa ganhar uma vantagem uma vez e depois pode voltar a jogar pares para os quais pick + guess = n. Portanto, os equilíbrios de Nash para um único jogo não se generalizam trivialmente aos equilíbrios de Nash para o jogo repetido, o que permite estratégias mais complexas.

Peter Taylor
fonte
4
É possível que sua mágica contenha uma parte dos números de Hamming ? Certamente não contém todos eles, mas muitos ( ou todos? ) Estão na lista desse site.
GiantTree
@ GigiantTree, todos são números de Hamming. Observação interessante.
22413 Peter Peter
Não é à toa que seu bot está ficando louco. : D
mbomb007 13/02/2015
11

Quinn e Valor (Atualizado)

Quinn e Valor são um time de elite de guarda florestal. Com besta e garra, eles rasgam todo oponente ousa desafiá-lo.

import java.util.ArrayList;
import java.util.List;

interface Champion extends Player {
}

/*
 * Quinn and Valor are an elite ranger team. With crossbow and claw, they ...
 */
public class QuinnAndValor implements Champion {

    private final Champion quinn = new Quinn();
    private final Champion valor = new Valor();

    private int checker;
    private int myScore, opScore;
    private boolean ulted;
    private boolean teemoDetected;
    private boolean quinnNeverLose, valorNeverLose;
    private int quinnScore, valorScore;
    private int quinnRound, valorRound;

    public QuinnAndValor() {
        checker = check() ? 0 : 1;
    }

    // Check if is a fine use
    private static boolean check() {
        return Thread.currentThread().getStackTrace()[3].getClassName().equals(
                "Tournament");
    }

    @Override
    public String getName() {
        return quinn + " and " + valor;
    }

    @Override
    public int[] getMove(String[] args) {
        // Punish for bad usage
        switch (checker) {
        case 1:
            checker++;
            return new int[] { -1, -1 };
        case 2:
            checker++;
            return null;
        case 3:
            throw new Error("Mua he he heh!");
        default:
            if (checker > 0)
                throw new Error("Mua he he heh!");
            break;
        }

        int round = args[0].length();
        if (round == 0) {
            // Buy starting items
            myScore = opScore = 0;
            teemoDetected = false;
            quinnNeverLose = valorNeverLose = true;
            quinnScore = valorScore = quinnRound = valorRound = 0;
            ((Valor) valor).reset();
        }

        if (ulted = useUltimate(args)) {
            valorRound++;
            return valor.getMove(args);
        } else {
            quinnRound++;
            return quinn.getMove(args);
        }
    }

    /*
     * Quinn's ultimate has a lengthy cool-down, especially at lower ranks, so
     * we have to use it only when needed.
     */
    private boolean useUltimate(String[] args) {
        int round = args[0].length();
        int lastMyScore = myScore;
        int lastOpScore = opScore;
        myScore = Integer.parseInt(args[2]);
        opScore = Integer.parseInt(args[5]);
        int score = (myScore - opScore) - (lastMyScore - lastOpScore);
        if (ulted) {
            valorScore += score;
            valorNeverLose &= score >= 0;
        } else {
            quinnScore += score;
            quinnNeverLose &= score >= 0;
        }

        if (round < 100) {
            // Haven't hit level 6 yet
            return false;
        }

        if (myScore > opScore) {
            // We're already winning. Press on with strategy impossible to lose
            if (quinnNeverLose && quinnRound >= 50)
                return false;
            if (valorNeverLose && valorRound >= 50)
                return true;
        } else if (myScore < opScore) {
            // Although Quinn can blind others to counter them, she can be
            // counter be Teemo who also has blind! Don't fall for this!
            if (!teemoDetected) {
                teemoDetected = true;
                for (int i = round - 20; i < round; i++)
                    if (args[3].charAt(i) + args[4].charAt(i) != 'e')
                        teemoDetected = false;
            }
            if (teemoDetected)
                return true;
        }

        if (valorRound < 100) {
            // If we never use our ultimate, how can we know how strong it is?
            return true;
        }

        if (quinnScore < 0 && valorScore < 0)
            return valorRound < quinnRound;
        else
            return quinnScore * valorRound < valorScore * quinnRound;
    }

    @Override
    public String toString() {
        return getName();
    }

    /*
     * Quinn is a female Demacian elite ranger.
     * 
     * @see Valor
     */
    public static class Quinn implements Champion {
        @Override
        public String getName() {
            return "Quinn";
        }

        /*
         * Magic!
         */
        @Override
        public int[] getMove(String[] args) {
            int t = (int) ((Math.sqrt(Math.random() * 168 + 1) - 1) / 2);
            return new int[] { 5 - t, t };
        }

        @Override
        public String toString() {
            return getName();
        }
    }

    /*
     * Valor is Quinn's Demacian eagle.
     * 
     * @see Quinn
     */
    public static class Valor implements Champion {
        @Override
        public String getName() {
            return "Valor";
        }

        private int lastRound;
        private double[][] c;

        public void reset() {
            lastRound = 0;
            c = new double[6][6];
        }

        /*
         * Magic!
         */
        @Override
        public int[] getMove(String[] args) {
            int round = args[0].length();
            int[] b = new int[6];
            for (int i = round - 12; i < round; i++)
                b[args[0].charAt(i) - '0']++;
            {
                double deWeight = Math.pow(0.95, round - lastRound);
                for (int i = 0; i < 6; i++)
                    for (int j = 0; j < 6; j++)
                        c[i][j] *= deWeight;
                double weight = 1;
                for (int i = round - 1; i >= lastRound; i--) {
                    c[args[3].charAt(i) - '0'][args[4].charAt(i) - '0'] += weight;
                    weight *= 0.95;
                }
            }
            lastRound = round;

            List<int[]> pq = new ArrayList<>(1);
            double e = Integer.MIN_VALUE;
            for (int i = 0; i < 6; i++)
                for (int j = 0; j < 6; j++) {
                    double f = 0;
                    for (int k = 0; k < 6; k++)
                        f += (i + j) * c[j][k];
                    for (int k = 0; k < 6; k++)
                        f -= (i + k) * c[k][i];
                    // recently played moves are dangerous
                    f -= b[i] * b[i] * ((round + 11) / 12);
                    if (f >= e) {
                        if (f > e) {
                            pq.clear();
                            e = f;
                        }
                        pq.add(new int[] { i, j });
                    }
                }
            return pq.get((int) (Math.random() * pq.size()));
        }

        @Override
        public String toString() {
            return getName();
        }
    }
}

Eles quase sempre vencem todas as soluções Java da minha máquina.

Editar:

Admito que Quinn e Valor não conseguiram duelar com o Historian, mas ainda tenho boa fé neles para vencer o torneio.

Meu princípio é que, para qualquer solução choice + guess == 5, também choice + guess == 5brinque com os donatários mantendo sua vantagem.

Atualizar:

Bem ... tudo ficou complicado.

johnchen902
fonte
1
Eu gosto da referência de League of Legends. Eu realmente quero fazer um bot Teemo agora. :)
mbomb007
6

Estudioso

O estudioso tenta aprender com os movimentos de seu oponente, escolhendo aquele que seu oponente menos adivinhou e adivinhando aquele que seu oponente mais usou. Mas a teoria não é tudo, então o Scholar não se sai muito bem ...

import java.util.HashMap;

public class Scholar implements Player
{
    public static int[] pm = new int[6];
    public static int[] pg = new int[6];
    public static HashMap<Integer, Integer> lm = new HashMap<>();
    public static HashMap<Integer, Integer> lg = new HashMap<>();

    public String getName()
    {
        return "Scholar";
    }

    public int[] getMove(String[] a)
    {
        int r = a[0].length();
        for (int i = 0; i < 6; i++) { pm[i]=0; pg[i]=0; }
        for (int i = 0; i < a[3].length(); i++) {
            int m = Integer.parseInt(String.valueOf(a[4].charAt(i)));
            int g = Integer.parseInt(String.valueOf(a[3].charAt(i)));
            pm[m]++; pg[g]++;
        }
        for (int i = 0; i < pm.length; i++) { lm.put(i, pm[i]); lg.put(i, pg[i]); }

        if (r < 1) {
            return new int[] { 3, 3 };
        } else {

            int mm = lm.entrySet().stream().min((x, y) -> x.getValue() > y.getValue() ? 1 : -1).get().getKey();
            int mg = lg.entrySet().stream().max((x, y) -> x.getValue() > y.getValue() ? 1 : -1).get().getKey();
            return new int[] { mm, mg };
        }   
    }
}
Thrax
fonte
6

DeltaMax

(Atualizado para não usar arquivos e adicionado uma nova seção. Também modificado para não ficar mais preso na primeira seção.)

Consiste em algumas estratégias que começam simples e se tornam mais complexas - se você desmarcar uma, ela será direcionada para a próxima seção.

  • Seção 1: Adivinhe {0, 5}consistentemente
  • Seção 2: verifique se suas últimas quatro suposições formam um padrão constante, linear ou quadrático e continue adivinhando o padrão até que ele se quebre
  • Seção 3: verifique se você adivinha uma quantidade anormalmente baixa de algum número (menor que 1/13) e escolha esse número
  • Seção 4: Analise os bigrams em suas escolhas e veja o que é mais provável que venha a seguir
  • Seção 5: Examine as 100 rodadas anteriores e escolha o (choice, guess)par que teria a melhor expectativa, ponderado para que as rodadas recentes sejam mais importantes
  • Seção final: adivinhar aleatoriamente, com maior probabilidade de ter escolhas baixas e adivinhações altas. Se você chegar aqui, o DeltaMax desistiu e gostaria de dizer "bom jogo".

Para descobrir qual camada foi usada no final, remova o comentário do

if (myChoices.length == 999) { System.out.println(strat); }

linha.

Desculpas pelo horrível Java, passei minha tarde juntando pedaços e reaprendendo a linguagem :)

import java.io.*;
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;

public class DeltaMax implements Player
{
    private int strat = 100;

    public String getName() { return "DeltaMax"; }

    public int[] toInts(String s) {
        char [] chars = s.toCharArray();
        int[] ints = new int[chars.length];

        for (int i = 0; i < chars.length; i++){
            ints[i] = Integer.parseInt(Character.toString(chars[i]));
        }

        return ints;
    }

    public int mod6(int n) {
        n = n % 6;
        if (n < 0) { n += 6; }
        return n;
    }

    public int[] getMove(String [] args)
    {
       int[] myChoices = toInts(args[0]);
       int[] myGuesses = toInts(args[1]);
       int myScore = Integer.parseInt(args[2]);
       int[] opponentChoices = toInts(args[3]);
       int[] opponentGuesses = toInts(args[4]);
       int opponentScore = Integer.parseInt(args[5]);

       int rounds = myChoices.length;

       if (rounds == 0) { strat = 100; }
       Random r = new Random();

       // if (myChoices.length == 999) { System.out.println(strat); }

       if (strat == 100) { // Section 1 - {0, 5}
           if (opponentScore - myScore > 21 || (opponentScore >= myScore && rounds > 100)) {
               strat = 200;
           } else {
               return new int[] {0, 5};
           }
       }

       if (strat == 200) { // Section 2 - Mini interpolator
           int w = opponentChoices[opponentChoices.length - 4];
           int x = opponentChoices[opponentChoices.length - 3];
           int y = opponentChoices[opponentChoices.length - 2];
           int z = opponentChoices[opponentChoices.length - 1];

           if (w == x && x == y && y == z) { // Constant
               return new int[] { r.nextInt(4) + 2, w };
           }

           if (mod6(x-w) == mod6(y-x) && mod6(y-x) == mod6(z-y)) { // Linear
               return new int[] { r.nextInt(4) + 2, mod6(z + (z-y)) };
           }

           if (mod6((y-x) - (x-w)) == mod6((z-y) - (y-x))) { // Quadratic
               return new int[] { r.nextInt(4) + 2, mod6((z-y) + mod6((y-x) - (x-w))) };
           }

           strat = 300;
       }

       if (strat == 300) { // Section 3 - exploit least guessed
           int [] counts = new int[6];

           for (int i = 0; i < rounds; i++) {
               counts[opponentGuesses[i]] += 1;
           }

           int minCount = rounds;

           for (int i = 0; i < 6; i++) {
               if ((counts[i] <= 1 || counts[i] * 13 < rounds) && counts[i] < minCount) {
                   minCount = counts[i];
               }
           }

           if (minCount == rounds) {
               strat = 400;
           } else {
               ArrayList<Integer> choices = new ArrayList<Integer>();

               for (int i = 0; i < 6; i++) {
                   if (counts[i] == minCount) {
                       choices.add((Integer) i);
                   }
               }

               int choice = choices.get(r.nextInt(choices.size()));

               // {0, 0} is about the worst thing you can do, so DeltaMax tries to avoid that
               if (choice == 0) {
                   return new int[] { 0, r.nextInt(4) + 2 };
               } else {
                   return new int[] { choice, r.nextInt(6) };
               }
           }
       }

       if (strat == 400) { // Section 4 - bigrams
           if (opponentScore - myScore > 42 || (opponentScore >= myScore && rounds > 300)){
               strat = 500;
           } else {
               int[] opponentScores = new int[6];
               int opponentLast = opponentChoices[opponentChoices.length - 1];

               int[] myScores = new int[6];
               int myLast = myChoices[myChoices.length - 1];

               for (int i = 0; i < opponentChoices.length - 1; i++) {
                   if (opponentChoices[i] == opponentLast) {
                       opponentScores[opponentChoices[i+1]] += 1;
                   }

                   if (myChoices[i] == myLast) {
                       myScores[myChoices[i+1]] += 1;
                   }
               }

               int maxIndex = -1;
               int maxScore = 0;

               int minIndex = -1;
               int minScore = rounds;

               for (int i = 0; i < 6; i++) {
                   if (opponentScores[i] >= maxScore) {
                       maxScore = opponentScores[i];
                       maxIndex = i;
                   }

                   if (myScores[i] <= minScore) {
                       minScore = myScores[i];
                       minIndex = i;
                   }
               }

               if (minIndex == 0 && maxIndex == 0) {
                   return new int[] { 0, r.nextInt(4) + 2 };
               } else {
                   return new int[] { minIndex, maxIndex };
               }
           }
       }

       if (strat == 500) { // Section 5 - best expectation
           if (opponentScore - myScore > 84 || (opponentScore >= myScore && rounds > 800)){
               strat = 573;
           } else {
               int minLen = Math.min(rounds, 100);

               double bestScore = 0;
               int bestGuess = 0;
               int bestChoice = 5;

               for (int guess = 0; guess < 6; guess++) {
                   for (int choice = 0; choice < 6; choice++) {
                       double score = 0;
                       int start = rounds - minLen;

                       for (int i = start; i < rounds; i++) {
                           if (opponentGuesses[i] == choice && opponentChoices[i] != guess) {
                               score -= (choice + opponentChoices[i]) * ((double) i - start) / minLen;
                           } else if (opponentGuesses[i] != choice && opponentChoices[i] == guess) {
                               score += (choice + opponentChoices[i]) * ((double) i - start) / minLen;
                           }
                       }

                       if (score > bestScore) {
                           bestScore = score;
                           bestGuess = guess;
                           bestChoice = choice;
                       }
                   }
               }

               if (bestChoice == 0 && bestGuess == 0) {
                   return new int[] { r.nextInt(4) + 2, bestGuess };
               } else {
                   return new int[] {bestChoice, bestGuess};
               }
           }
       }

       // Section final - hope for the best
       int num = (int) Math.floor(Math.sqrt(r.nextInt(35)));
       return new int[] {5 - num, num};
    }
}
Sp3000
fonte
Com a implementação atual do controlador, não há necessidade de salvar coisas em um arquivo se os dados forem usados ​​apenas para um único jogo. ou seja, private int strat;é bom o suficiente.
31915
@ johnchen902 Obrigado, eu não sabia que poderia fazer isso. Isso facilita muito as coisas.
Sp3000 12/02/2015
6

Historiador

(Atualizado: mesma lógica, código mais curto e 100 vezes mais rápido, mas você pode usar apenas um bot do Historian em um torneio.)

Usa aleatoriamente ponderada para escolher um par de adivinhação com base na eficácia de usar apenas esse par contra o histórico anterior do oponente. Os pesos são os quadrados das pontuações alcançáveis.

public class Historian implements Player {
    private static java.util.Random r = new java.util.Random();
    private static int[] sc=new int[36]; //reseted between games, use only one Historian bot
    public String getName() {return "Historian";}
    public int[] getMove(String [] a) {
        if (a[3].length()==0)  {sc=new int[36]; for(int i=0;i<6;i++) sc[i*6+(5-i)]=5-i;}
        else {int t=a[3].charAt(a[3].length()-1)-'0'; int g=a[4].charAt(a[3].length()-1)-'0';
            for(int i=0; i<6; i++) {sc[i*6+t]+=i+t; sc[g*6+i]-=t+g;}}
        int sum=0; for(int i=0; i<36; i++) {sum+=(sc[i]<1)?1:sc[i]*sc[i];}
        int seed=r.nextInt(sum);int mt=-1;
        while (seed>=0) {seed-=(sc[++mt]<1)?1:sc[mt]*sc[mt];}  
        return new int[] {(int)(mt/6),mt%6};} }

Bate Quinn and Valor (não mais) e perde para Morra Cowbell. No torneio com a maioria dos bots Historianvem em segundo Quinn and Valor.

randomra
fonte
Bem, é bom ver que ganhei na máquina de alguém. Estou perdendo o atual quadro de líderes oficial . Eu estava pensando que é por causa da má sorte ou de algum erro sutil imprevisto.
31516 John DeLonge:
@ johnchen902 Devo ter espancado alucinado Morra Cowbell. Editou a postagem. Você pode excluir comentários, se eles se tornarem obsoletos.
Random # 12/02
Acho que posso ganhar 75% do nosso duelo agora após a minha atualização!
31515
5

Extrapolador (v1.1)

Extrapolação extrema de um dos equilíbrios de Nash de um jogo mais simples.

Eu apoio o formato de resposta concisa! (No estilo python.)

public class Extrapolator implements Player { 
    private static java.util.Random r = new java.util.Random();
    public String getName() { return "Extrapolator"; }
    public int[] getMove(String [] args) {
        int t=-1;
        for(int c=15,s=r.nextInt(60);s>=0;s-=c,c-=2,t++);
        return new int[] {t,5-t}; } }

Parece amarrar com a vaca mágica (Morra Cowbell) e supera outras entradas que eu verifiquei.

randomra
fonte
1
Mova o Random r para um campo estático, para não inicializá-lo toda vez, isso ajudará no desempenho geral!
Falco
Por que a mudança na distribuição?
Peter Taylor
4

Na moda

Trendy dá uma olhada nos movimentos passados ​​do oponente, ponderando-os pela recência. Adivinha o mais pesado, e escolhe um que se deslocou um pouco disso. Aqui está em toda a sua glória:

public class Trendy implements Player{public String getName(){return "Trendy";}public int[]getMove(String[]a){float h=0,c[]=new float[6];int i=0,l=a[3].length(),p=0;for(;i<l;)c[a[3].charAt(i++)-48]+=(float)i/l;for(i=0;i<6;i++)if(c[i]>h)h=c[p=i];return new int[]{(p+2)%6,p};}}    

A única coisa com a qual posso compará-lo agora é Cowbell. Perde por uma pequena margem a maior parte do tempo, mas sai por cima com frequência suficiente para o meu gosto. Vamos ver como isso acontece com mais concorrentes.

Geobits
fonte
7
Você poderia formatar o código em várias linhas? Isso não é código de golfe ... #
114415 mbomb007
7
@ mbomb007 Consome menos espaço dessa maneira. Uma das dores de KotHs em geral é toda a rolagem para observar as entradas. Descrevi o que faz e é muito simples para as partes interessadas formatá-lo.
Geobits
4

Random Guesser

Isso é realmente direto. Ele efetivamente lança um d6 e adiciona outro rolo ao rolo anterior para adivinhar. Não vencerá, mas fornecerá uma boa referência.

import java.util.Random;

public class RandomGuesser implements Player {
    private final Random rnd = new Random();
    public String getName() { return "RandomGuesser"; }

    public int[] getMove(String[] args) {
        return new int[] { rnd.nextInt(6), rnd.nextInt(6) };
    }
}
mbomb007
fonte
4

Confuso, Python 3

Uma entrada desnecessariamente complicada. Mesmo eu não sei o que faz.

import sys
from random import *

if len(sys.argv) == 7:
    mn,mg,ms,on,og,os = [list(map(int, v)) for v in sys.argv[1:]]
    s,t = sum(mn+on)%5, sum(mg+og)%5
    n = [0]*3+list(range(6))*5+[5,0,5]
    m = [1,0,5,4]+n[:-2:s//9+1]
    numoptions = [n.extend(n[i+s::5+t]+[i]*i*(6+t)) for i in n[:]] and n
    guessoptions = [m.extend(m[i+t//2::8]+[i]*i*(5+s)) for i in m[:]] and m
    num = choice(numoptions)
    guess = choice(guessoptions)
else:
    num, guess = randint(0, 5), randint(0, 5)

sys.stdout.write('%u %u\n' % (num, guess))

Embora esse algoritmo avançado pareça ter um desempenho pior que aleatório neste torneio e use memória e tempo de execução significativos, ele possui resultados impressionantes para determinados valores de 5 ;-)

Cavaleiro Lógico
fonte
4

Rainbolt

Toma a diferença entre os dois últimos números que nosso oponente adivinhou, acrescenta que ao último palpite de nosso oponente, encontra o módulo e evita escolher esse número a todo custo. Por exemplo, se você adivinhar {5,4,3} (diminuindo em um), evitaríamos escolher 2 a todo custo.

Toma a diferença entre os dois últimos números que nosso oponente escolheu, acrescenta isso à última escolha do oponente e adivinha esse número. Por exemplo, se você adivinhar {1,4,5,2} (aumentando em três), adivinharemos 5.

Evita rolos inúteis ou muito próximos de inúteis.

public class Rainbolt implements Player {

    public String getName() { 
        return "Rainbolt"; 
    }

    public int[] getMove(String[] args) {
        int[] yourChoices = toIntArray(args[3]);
        int[] yourGuesses = toIntArray(args[4]);

        int myChoice;
        if (yourGuesses.length > 1) {
            int latest = yourGuesses[yourGuesses.length - 1];
            int secondLatest = yourGuesses[yourGuesses.length - 2];
            int numberToAvoid = (2 * latest - secondLatest + 6) % 6;
            do {
                myChoice = rollRandom();
            } while (myChoice == numberToAvoid);
        } else { 
            myChoice = rollRandom();
        }

        int myGuess;
        if (yourChoices.length > 1) {
            int latest = yourChoices[yourChoices.length - 1];
            int secondLatest = yourChoices[yourChoices.length - 2];
            myGuess = (2 * latest - secondLatest + 6) % 6;
        } else { 
            myGuess = rollRandom();
        }

        if ((myChoice + myGuess) < 3) {
            do {
                myGuess = rollRandom();
            } while ((myChoice + myGuess) < 3);
        }

        return new int[] { myChoice, myGuess };
    }

    private static int[] toIntArray(String arg) {
        int[] result = new int[arg.length()];
        for (int i = 0; i < arg.length(); i++)
            result[i] = Character.getNumericValue(arg.charAt(i));
        return result;
    }

    private static int rollRandom() {
        return (int) (Math.random() * 6);
    }
}
Rainbolt
fonte
Não torne seu getMove()método estático. Você não pode implementar um método não estático como esse (pelo menos não no Java 8).
GiantTree 11/02
@GiantTree Obrigado por capturar isso.
Rainbolt
3

Bot evoluído

Eu desenvolvi esse bot para ser o melhor bot aleatório.

import java.util.Arrays;

public class EvolvedBot implements Player {

    private static final double MUTATION_RATE = .2;
    private static final double CROSS_OVER_RATE = .5;

    private final double[] pickProbabilities;
    private final double pickSum;
    private final double[] guessProbabilities;
    private final double guessSum;

    public EvolvedBot(){
        this(new double[]{1.0069058661897903, 0.8949716031797937, 0.5249198534098369, 0.437811964976626, 0.2630925750209125, 0.4862172884617061},
                new double[]{0.6336558074769376, 0.13700756148363913, 0.9586621925124863, 0.11223159366330251, 0.8931390659502754, 0.662974949440039});
    }

    public EvolvedBot(double[] pickProbabilities, double[] guessProbabilities) {
        this.pickProbabilities = pickProbabilities;
        this.guessProbabilities = guessProbabilities;
        pickSum = Arrays.stream(pickProbabilities).sum();
        guessSum = Arrays.stream(guessProbabilities).sum();
    }

    @Override
    public String getName() {
        return "EvolvedBot"/* + ": " + Arrays.toString(pickProbabilities) + Arrays.toString(guessProbabilities)*/;
    }

    @Override
    public int[] getMove(String[] args) {
        int[] move = new int[]{5, 5};
        double pick = Math.random() * pickSum;
        double guess = Math.random() * guessSum;
        for (int i = 0; i < 6; i++){
            if (pick >= 0) {
                pick -= pickProbabilities[i];
                if (pick < 0) {
                    move[0] = i;
                }
            }
            if (guess >= 0){
                guess -= guessProbabilities[i];
                if (guess < 0){
                    move[1] = i;
                }
            }
        }
        return move;
    }

    public EvolvedBot mutate(double mutationRate){
        double[] pickProbabilities = Arrays.copyOf(this.pickProbabilities, 6);
        double[] guessProbabilities = Arrays.copyOf(this.guessProbabilities, 6);

        for (int i = 0; i < 6; i++){
            pickProbabilities[i] = Math.max(pickProbabilities[i] + (Math.random() * 2 - 1) * mutationRate, 0);
        }

        for (int i = 0; i < 6; i++){
            guessProbabilities[i] = Math.max(guessProbabilities[i] + (Math.random() * 2 - 1) * mutationRate, 0);
        }

        return new EvolvedBot(pickProbabilities, guessProbabilities);
    }

}
O número um
fonte
3

Popularidade, Python 3

Calcule a estimativa com base em números populares usados ​​no passado pelo oponente. Os números usados ​​recentemente têm mais peso. A escolha do número geralmente é a mesma que o palpite.

import sys
from random import *

if len(sys.argv) == 7:
    mn,mg,ms,on,og,os = [list(map(int, v)) for v in sys.argv[1:]]
    n = list(range(6))
    guess = choice(n + on[-100:] + on[-20:]*8)
    num = choice(n + [guess]*6)
else:
    num, guess = randint(0, 5), randint(0, 5)

sys.stdout.write('%u %u\n' % (num, guess))
Cavaleiro Lógico
fonte
3

Interpolador

(Comutado para Java, pois o Python estava causando problemas)

Usa interpolação polinomial nas últimas 10 opções do oponente para calcular o próximo número do oponente, depois faz o mesmo com suas próprias escolhas e evita a escolha desse número. Além disso, o Interpolator tem um leve viés contra a escolha de 0 ou 5, e sua escolha às vezes é afetada pelo seu palpite:

  • Se adivinhar 0, nunca escolherá 0
  • Se adivinhar 5, sempre escolherá 0 ou 1
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

public class Interpolator implements Player
{
    private final int TAIL_LENGTH = 10;

    public String getName()
    {
        return "Interpolator";
    }

    public int[] toInts(String s) {
        char [] chars = s.toCharArray();
        int[] ints = new int[chars.length];

        for (int i = 0; i < chars.length; i++){
            ints[i] = Integer.parseInt(Character.toString(chars[i]));
        }

        return ints;
    }

    public int mod6(int n) {
        n = n % 6;
        if (n < 0) { n += 6; }
        return n;
    }

    public int interpolate(int[] nums){
        boolean allEqual = true;

        for (int i = 0; i < nums.length; i++){
            if (nums[i] != nums[0]){
                allEqual = false;
            }
        }

        if (allEqual) {
            return nums[0];

        } else {
            int [] newNums = new int[nums.length - 1];

            for (int i = 0; i < nums.length - 1; i++){
                newNums[i] = nums[i+1] - nums[i];
            }

            return nums[nums.length - 1] + interpolate(newNums);
        }
    }

    public int[] tail(int[] nums) {
        int minLength = Math.min(TAIL_LENGTH, nums.length);
        int[] tailArray = new int[minLength];

        for (int i = 0; i < minLength; i++){
            tailArray[i] = nums[nums.length - minLength + i];
        }

        return tailArray;
    }

    public int[] getMove(String [] args)
    {
        Random r = new Random();

        if (args[0].length() == 0){
            return new int[] {r.nextInt(5), r.nextInt(5)};
        }

        int[] myChoices = toInts(args[0]);
        int[] opponentChoices = toInts(args[3]);
        int[] opponentGuesses = toInts(args[4]);

        int guess = mod6(interpolate(tail(opponentChoices)));
        int avoid = mod6(interpolate(tail(myChoices)));

        if (guess == 5){ return new int[] {r.nextInt(2), 5}; }

        int[] choiceArray = {0, 1, 1, 2, 2, 3, 3, 4, 4, 5};
        ArrayList<Integer> choices = new ArrayList<Integer>();
        for (int i = 0; i < choiceArray.length; i++) { choices.add(choiceArray[i]); }

        choices.removeAll(Collections.singleton((Integer) avoid));
        if (guess <= 0) { choices.removeAll(Collections.singleton((Integer) 0)); }
        int choice = choices.get(r.nextInt(choices.size())); 

        return new int[] {choice, guess};
    }
}
Sp3000
fonte
3

CounterBot

Não contraria ninguém, mas conta de 0 a 5 em um círculo ( 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4 ...)

import java.util.Random;

public class Counter implements Player {

    int lastChoice = new Random().nextInt(6); //Chooses a random starting number

    public String getName() {
        return "CounterBot";
    }

    public int[] getMove(String[] args) {
        int[] oChoices = new int[6]; //Array to store the amount of individual choices of the opponent

        for (int i = 0; i < args[3].length(); i++) {
            int index = Integer.parseInt(String.valueOf(args[3].charAt(i))); //get that choice
            oChoices[index]++; //Increment the number corresponding the choice
        }
        int guess = 0, last = 0;
        for (int i = 0; i < oChoices.length; i++) { //Increment over the choices' array
            if (oChoices[i] > last) { //If the number has been chosen more often than the one before
                last = oChoices[i]; //Set the new maximum value (later the last maximum value)
                guess = i; //Set it as the next guess
            }
        }
        lastChoice++; //Increment our choice
        lastChoice %= 6; //Make sure it's within the bounds of 0-5 ie. modulo 6 (6 modulo 6 = 0)
        return new int[]{lastChoice, guess}; //return our choice and guess
    }
}
GiantTree
fonte
2

Basilisco, Python

Segundo a lenda, o Basilisco é o rei das serpentes. ( fonte ) Imaginei que esse era um nome apropriado para um bot que toca "The Noble Game Of Kings" e está escrito em python. = D Este bot causa medo no coração dos outros bots e causa a morte com um único olhar.

import sys
import random

args = sys.argv
argc = len(args)
if argc < 6:
    sys.exit()

myChoices = args[1]
myGuesses = args[2]
myScore = args[3]
opponentChoices = args[4]
opponentGuesses = args[5]
opponentScore = args[6]

if len(myChoices) == 0:
    print (random.randint(0, 5))
    print (random.randint(0, 5))
    sys.exit()

guesses = [0, 0, 0, 0, 0, 0]
for char in opponentGuesses:
    i = int(char)
    guesses[i] += 1

#Will default towards smaller guesses to minimize opponent winnings
#For example, if the guess list is
#[5, 3, 7, 3, 4, 8]
#This will return 1. (index of the first 3)
myNextMove = guesses.index(min(guesses))

list = [
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0]]
i = 0

while i < len(myGuesses) - 1:
    myGuess = int(myGuesses[i])
    opponentResponse = int(opponentChoices[i+1])
    list[myGuess][opponentResponse] += 1
    i += 1

myPreviousGuess = int(myGuesses[-1])
relevantList = list[myPreviousGuess]

#Defaults towards higher moves.
#For example, if the list is
#[3, 8, 6, 8, 0, 7]
#This will return 3 (index of the last 8)
highestValue = -1
highestIndex = -1
for i in range(len(relevantList)):
    if relevantList[i] >= highestValue:
        highestValue = relevantList[i]
        highestIndex = i


myNextGuess = highestIndex

print (myNextMove)
print (myNextGuess)

Isso é executado em uma estratégia bastante simples. Não espero que vença, mas foi divertido escrever. Este também é o meu primeiro desafio do KoTH, por isso estou animado para ver como ele se sai.

Como escolhe seu próximo passo.

O Basilisco sempre faz o movimento que seu oponente adivinhou o menor número de vezes. Em caso de empate, ele escolherá o número menor. (para minimizar o número de pontos do oponente.)

Como escolhe seu próximo palpite.

O Basilisco escolherá a resposta mais provável ao seu palpite anterior. Por exemplo, se da última vez, adivinhou um 3, ele retornará todas as vezes anteriores que adivinhou um 3 e, em seguida, retornará o movimento adversário mais comum que vem após um palpite de 3. Em caso de empate , ele selecionará o número maior (para maximizar o número de pontos que ele poderia fazer).

Em uma nota técnica, isso funcionará corretamente? Print () é suficiente ou devo usar algo como sys.stdout.write () como os outros pythonistas fizeram?

DJMcMayhem
fonte
sys.stdout.write () funciona em qualquer Python. print () funciona apenas no Python 3. No entanto, tudo bem.
TheNumberOne
Não, print () também funciona, tenho certeza disso. Os parênteses são opcionais no 2.x
DJMcMayhem
De acordo com isso , eles funcionam de maneira diferente. No entanto, a maneira como você o usa, não importa.
TheNumberOne
Mas isso faz alguma diferença?
DJMcMayhem
Aparentemente não.
TheNumberOne
2

Idem

Isso se transforma no oponente, mas atrasado por um palpite / escolha.

import java.util.Random;

public class Ditto implements Player {
    private final Random rnd = new Random();
    public String getName() { return "Ditto"; }

    // myChoices myGuesses myScore oppChoices oppGuesses oppScore
    public int[] getMove(String[] args) {
        if(args[0] == null || args[0].isEmpty()) {
            return new int[] { rnd.nextInt(6), rnd.nextInt(6) };
        }
        int[] myChoices = toIntArray(args[0]);
        int[] myGuesses = toIntArray(args[1]);
        //int myScore = Integer.parseInt(args[2]);
        int[] oppChoices = toIntArray(args[3]);
        int[] oppGuesses = toIntArray(args[4]);
        //int oppScore = Integer.parseInt(args[5]);

        return new int[] { oppChoices[oppChoices.length-1], oppGuesses[oppGuesses.length-1] };
    }

    private static int[] toIntArray(String arg) {
        int[] result = new int[arg.length()];
        for (int i = 0; i < arg.length(); i++)
            result[i] = Character.getNumericValue(arg.charAt(i));
        return result;
    }
}
mbomb007
fonte
1

NullifierBot, Java

Sempre joga 0 para minimizar os ganhos do adversário. Se o oponente adivinhar meu número, ele só ganha o que jogou.

Sempre adivinha 5 para maximizar meus ganhos. Como não consigo obter nenhum ponto no meu arremesso, quero receber o maior número possível do oponente. Eu poderia adivinhar aleatoriamente, mas onde está a graça nisso?

public class NullifierBot implements Player
{
    public String getName()
    {
        return "NullifierBot";
    }

    public int[] getMove(String [] args)
    {
        // always throws 0 to minimize opponents score
        // always guesses 5 to maximize my score
        return new int[] {0, 5}; 
    }
}
Brian J
fonte
Eu estou supondo que este bot vai fazer terrivelmente. Qualquer bot que use probabilidades talvez até consiga adivinhar logo após o primeiro.
mbomb007
@ mbomb007 Mas não é o pior! Embora tenha um desempenho pior que o seu RandomBot.
Brian J
1

Erratica, Java

Não é ótimo, mas foi originalmente projetado para ser aleatório, até que o valor da troca me ocorreu. Consegue perder consistentemente vs. Counter Bot> _ <

import java.util.Random;
class Erratica implements Player
{
    private final Random rnd = new Random();

    public String getName() {
        return "Erratica";
    }

    public int[] getMove(String[] args) {
        if(args[0] == null || args[0].isEmpty())
        {
            return new int[]{rnd.nextInt(4)/3+4,rnd.nextInt(4)/3};
        }
        int[] myChoices = toIntArray(args[0]);
        int[] myGuesses = toIntArray(args[1]);
        int myScore = Integer.parseInt(args[2]);
        int[] opponentChoices = toIntArray(args[3]);
        int[] opponentGuesses = toIntArray(args[4]);
        int opponentScore = Integer.parseInt(args[5]);
        int round = opponentChoices.length + 1;
        int choice=0;
        int guess=0;
        if(round<7)
        {
            if(rnd.nextFloat()<(0.1f*(float)round-0.1f))
            {
                choice=(opponentChoices[round-2]+opponentGuesses[round-2])%6;
            }else
            {
                choice=rnd.nextInt(6);
            }
            if(rnd.nextFloat()<(0.1f*(float)round-0.1f))
            {
                guess=opponentChoices[round-2];
            }else
            {
                guess=rnd.nextInt(6);
            }
            return new int[]{choice, rnd.nextInt(6)/5*(5-choice-guess)+guess};
        }else
        {
            int lastError=Math.abs(opponentGuesses[round-2]-myChoices[round-2]);
            for(int i=round-2; i>round-8;i--)
            {
                if(lastError<rnd.nextInt(6))
                {
                    lastError++;
                }else
                {
                    lastError--;
                }
                if(lastError<0)
                    lastError+=6;

            }
            lastError = lastError%6; //shouldn't change
            switch(rnd.nextInt(4))
            {
                case 0:
                    choice=(myChoices[round-2-lastError-round/10])%6;
                    break;
                case 1:
                    choice=(myChoices[lastError+round/10])%6;
                    break;
                default:
                    choice = rnd.nextInt(6);
                    break;
            }

            lastError=Math.abs(myGuesses[round-2]-opponentChoices[round-2]);
            for(int i=round-2; i>round-8;i--)
            {
                if(lastError<rnd.nextInt(6))
                {
                    lastError++;
                }else
                {
                    lastError--;
                }
                if(lastError<0)
                    lastError+=6;
            }
            lastError = lastError%6; //shouldn't change
            switch(rnd.nextInt(4))
            {
                case 0:
                    guess=(opponentChoices[round-2-lastError-round/10])%6;
                    break;
                case 1:
                    guess=(opponentChoices[lastError+round/10])%6;
                    break;
                default:
                    guess = rnd.nextInt(4);
                    break;
            }
        }

        if(myScore>opponentScore)
            switch(rnd.nextInt(2)){
                case 0:
                    choice=5-guess;
                    break;
                case 1:
                    guess=5-choice;
                    break;
                default:
                    break;
            }
        return new int[]{choice, guess};
    }

    private static int[] toIntArray(String arg) {
        int[] result = new int[arg.length()];
        for (int i = 0; i < arg.length(); i++)
            result[i] = Character.getNumericValue(arg.charAt(i));
        return result;
    }
}
Fongoid
fonte
1

Echo, Ruby

mychoices, myguesses, myscore, opponentchoices, opponentguesses, opponentscore = $*

unless mychoices
 puts "0 5"
 exit
end

if mychoices.size > 990 && myscore == '0'
  nextchoice = rand(1..5)
else
  nextchoice = opponentchoices[-1].to_i
end

recentchoices = opponentchoices[/.{0,100}$/]

nextguess = (0..5).max_by do |choice|
  (recentchoices.count(choice.to_s)+1) * (nextchoice + choice)
end

puts "%s %s"%[nextchoice,nextguess]

Reproduz a última jogada do oponente, com a teoria de que qualquer um pode fazer um bot que não pode prever. Adivinha com base no valor esperado usando uma amostra de cem movimentos.

histocrata
fonte
Estou recebendo este erro: echo.rb:3:in <main> ': método indefinido size' for nil:NilClass (NoMethodError). Parece ocorrer apenas no primeiro turno, quando não há histórico de movimentos.
PhiNotPi
Estranho, não aconteceu quando eu testei. Eu vou editar.
histocrat
Qual é a relevância da if (mychoices.size > 990 && myscore == '0') nextchoice = rand(1..5)peça?
Random # 16/02
Se estiver prestes a terminar em um empate sem gols (como aconteceria, por exemplo, contra si mesmo), ele começará a ser jogado aleatoriamente, já que ~ 50% de chance de vitória é melhor do que nada.
histocrat 16/02
1

KING FISHER

    import java.util.Random;
public class KingFisher {

    private Random rnd = new Random();
    private int wins = 0;
    private int loses = 0;
    private int median = 0;
    private int medianMoved = 0;
    private int[] weightedLow = {40,65,80,90,95};
    private int[] weightedHigh = {5,15,30,55,95};
    private boolean highWeightMethod = true;

    public String getName() {
        return "KingFisher";
    }

    public int[] getMove(String [] args)
    {
        char[] mc  = args[0].toCharArray();
        char[] mg  = args[1].toCharArray();
        char[] oc  = args[3].toCharArray();
        char[] og  = args[4].toCharArray();
        int len = mc.length;
        int currentGuess = 0;
        int currentChoice = 0;
        if(len < 10)
            return new int[] {rnd.nextInt(6),rnd.nextInt(6)}; 
        int[] guessWeight = {0,0,0,0,0,0};
        int[] guessWeightTotal = {0,0,0,0,0,0};
        for(int a = 0; a< len;a++)
            guessWeight[oc[a]-48]++;
        if(!highWeightMethod){

            int[] whiteList = {1,1,1,1,1,1};
            for(int b = 0;b<3;b++){

                int min = 0;
                int max = 0;
                int minIndex = 0;
                int maxIndex = 0;
                for(int a = 0;a<6;a++){

                    if(whiteList[a] == 1){

                        min = guessWeight[a];
                        max = guessWeight[a];
                        minIndex = a;
                        maxIndex = a;
                        break;
                    }
                }

                for(int a = 0; a<6;a++){

                    if(whiteList[a] == 1){

                        if(guessWeight[a]<min){

                            min = guessWeight[a];
                            minIndex = a;
                        }
                        if(guessWeight[a]>max){

                            max = guessWeight[a];
                            maxIndex = a;
                        }
                    }
                }
                guessWeight[maxIndex] = min;
                guessWeight[minIndex] = max;
                whiteList[maxIndex] = 0;
                whiteList[minIndex] = 0;
            }
        }

        for(int a = 0; a< 6;a++)
            for(int b = 0; b<=a;b++)
                guessWeightTotal[a]+=guessWeight[b];
        int randInt = rnd.nextInt(guessWeightTotal[5]);
        for(int a = 0; a<6;a++){

            if(randInt < guessWeightTotal[a]){
                currentGuess = a;
                break;
            }
        }

        if(mg[len-1] == oc[len-1]){
            wins++;
            median++;
        }
        if(og[len-1] == mc[len-1]){
            loses++;
            median--;
        }
        if(median > 2){

            medianMoved++;
            median = 0;
        }
        if(median < -2){

            medianMoved--;
            median = 0;
        }

        randInt = rnd.nextInt(95);
        if((wins-medianMoved)>(loses+medianMoved)){

            for(int a = 0; a<6;a++){

                if(randInt < weightedLow[a]){
                    currentChoice = a;
                    break;
                }
            }
        }
        else{

            for(int a = 0; a<6;a++){

                if(randInt < weightedHigh[a]){
                    currentChoice = a;
                    break;
                }
            }
        }
        if(medianMoved < -5){

            highWeightMethod = !highWeightMethod;
            medianMoved = 0;
        }
        return new int[] {currentChoice,currentGuess}; 

    }
}

Esse cara consiste em algoritmos de suposição ruim que usam matrizes ponderadas principalmente.

Vajura
fonte
Estará na próxima atualização.
PhiNotPi
1

Uh uh Eu sei o que você está pensando. "Ele vai pegar cinco ou algo mais?" Bem, para dizer a verdade em toda essa empolgação, eu não tenho certeza, mas sendo este o método .44, o método mais poderoso do mundo e sobrecarregaria sua pilha imediatamente, você precisa se fazer uma pergunta : "Sinto-me com sorte?"

Bem, sim, punk?

public class DirtyHarry implements Player {

    @Override
    public String getName() {
        return "DirtyHarry";
    }

    @Override
    public int[] getMove(String[] args) {
        return new int[]{5, 5};
    }
}
Capitão Homem
fonte