Morra, il nobile gioco dei re


28

sfondo

Il gioco di Morra è un gioco semplice. Nella versione "originale", diversi giocatori lanciano simultaneamente un numero 0-5 con le loro mani mentre indovina la somma totale delle mani di tutti. La versione che userò qui è stata modificata per aumentare il potenziale per una strategia non banale, ed è descritta di seguito:

  • Ci sono due giocatori.
  • Come nelle forbici da roccia, i giocatori si muovono contemporaneamente.
  • Ogni turno, ogni giocatore sceglie un numero 0-5 e indovina anche la scelta degli avversari di 0-5. Ciò significa che vengono emessi due numeri per turno. Per chiarire, entrambi i numeri devono essere compresi nell'intervallo 0-5, compreso.
  • Se indovini la scelta del tuo avversario correttamente ma il tuo avversario non ha indovinato correttamente, vinci un certo numero di punti pari alla somma dei due numeri giocati. Ad esempio, se i numeri giocati fossero 3 e 5, un'ipotesi corretta varrebbe 8 punti.
  • Se entrambi o nessuno dei giocatori indovina correttamente, non viene assegnato alcun punto.
  • La persona con più punti dopo 1000 round vince quella partita.

Il torneo

Il torneo si svolgerà in uno stile round-robin e verrà gestito creando ogni possibile accoppiamento del concorrente. Per ogni vittoria, il concorrente guadagna 2 punti vittoria. Ogni pareggio comporta 1 punto vittoria. Nessun punto vittoria viene guadagnato in perdita.

Intuitivamente, il vincitore del torneo sarà il concorrente con il maggior numero di punti vittoria contro altri.


Come entrare

Ci saranno due metodi per inviare i robot per competere. Il primo e molto preferito metodo è implementare un'interfaccia Java fornita dal controller. Il secondo metodo è scrivere un programma indipendente.

Vediamo prima il metodo Java. L'interfaccia è necessario implementare è Playere definisce due metodi: public String getName()identifica il bot, e public int[] getMove(String[] args)prende argscome un array di sei corde, mychoices myguesses myscore opponentchoices opponentguesses opponentscore. Un esempio è il seguente:

042 045 0 324 432 6

Questo significa che ho scelto 0 al primo turno e ho indovinato che il mio avversario avrebbe lanciato un 0. Il mio avversario ha lanciato un 3 e ha indovinato che avrei lanciato un 4. Nel terzo turno, il mio avversario ha fatto la supposizione corretta che avrei lanciato un 2, il che significa che guadagna 2 + 4 = 6 punti.

Il tuo metodo restituirà una matrice di due numeri interi, che sono la tua scelta e la tua ipotesi, rispettivamente. Un esempio è {4,2}per una scelta di 4 e un'ipotesi di 2.

Ecco un esempio di un bot Java completo scritto come metodo. Se lo desideri, il tuo invio deve solo includere ciò che sta accadendo nel getMovemetodo.

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;
    }
}

Come programma indipendente

Al momento sono limitato nel mio supporto per altre lingue. Oltre a Java, posso accettare programmi scritti in Python 3.4, Perl 5 o Ruby 2.1.5. Se esiste una lingua che molte persone sembrano desiderare, farò del mio meglio per aggiungerla.

L'input per il tuo programma saranno argomenti sulla riga di comando. Potrebbe apparire così:

perl awesomebot.plx 042 045 0 324 432 6

L'output del tuo programma dovrebbe essere la tua scelta seguita da una tua ipotesi, ciascuno seguito da uno spazio bianco.

Includi nella tua risposta l'esatto comando necessario per eseguirlo. Tieni presente che sto utilizzando Windows 8.1.


Regole extra

Stato di salvataggio e timeout

Il tuo programma sarà autorizzato a creare un file di testo nella directory locale, dove è possibile memorizzare informazioni. Queste informazioni verranno conservate per tutto il torneo ma successivamente cancellate. Assegna al file un nome che posso identificare.

C'è un limite di tempo di 500 millisecondi per la risposta del codice. La mancata risposta entro il termine (o la mossa non valida) comporterà la perdita di quel particolare incontro. Gli invii Java attualmente hanno un timeout passivo (che posso aggiornare a attivo), mentre gli invii non Java hanno un timeout attivo in cui il loro processo termina dopo 500 millisecondi.

Altre regole di presentazione

  • Sono consentiti invii multipli, purché rispettino le regole e non tag-team.
  • Ogni voce deve essere unica. Non è possibile effettuare una copia esatta della logica di un altro bot in una lingua diversa.
  • I robot non possono interagire tra loro (per formare una squadra di qualsiasi tipo).
  • Non puoi usare la logica degli altri robot all'interno del tuo bot per, per esempio, identificare il tuo concorrente e prevederne le azioni. Ovviamente puoi provare a determinare la strategia del tuo avversario.
  • Non tentare di pasticciare con il controller, altri concorrenti o il mio computer. Non connettersi a fonti di informazioni esterne.

Il controller

La versione corrente del controller è disponibile qui . È scritto in Java 8. Il file "Torneo" è il controller principale, che contiene anche l'elenco dei concorrenti (se si desidera ospitare le proprie competizioni).


Classifica

Non sono stato davvero in grado di aggiornare la classifica molto spesso. Sono piuttosto impegnato questo fine settimana. Per "piuttosto impegnato" intendo nessun accesso a un computer dalle 6:30 alle 21:30. Ecco i punteggi dopo 5 punti. Il bot "Echo" ha continuato a perdere per qualche motivo (potrebbe essere colpa mia, non ho ancora indagato).

  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          

Credito

Mille grazie a Rainbolt e Peter Taylor per il loro aiuto con il controller.


1
È stato aggiunto @ MartinBüttner Ruby 2.1.5.
PhiNotPi,

Come funziona il round robin? Player1 vs Player2 1000 volte, Player1 vs Player3 1000 volte ecc ... O è Player1 vs Player2 una volta quindi player1 vs player 3 una volta ecc ...
Vajura

@Vajura Un singolo torneo è composto da 1 battaglia tra ogni coppia. Una battaglia ha 1000 round, con il punteggio totale più alto alla fine della battaglia che determina chi ottiene i due punti vittoria. Il quadro di valutazione attuale mostra i punti vittoria totali dopo 40 tornei.
PhiNotPi,

Ci scusiamo per i ritardi nell'aggiornamento della scheda. Sono estremamente impegnato questo fine settimana. Aspettatevi e aggiornate stasera e domani mattina.
PhiNotPi,

Wow, non mi aspettavo che il mio bot funzionasse così bene! Inoltre, cosa significano i numeri per la prima serie di risultati ... numero di vittorie?
mbomb007,

Risposte:


17

Morra Cowbell

Per chiunque cerchi un significato nel nome di questo bot, il nome Morra mi fa pensare allo spazio italiano , quindi ho pensato che avevo bisogno di un nome che giocasse su quello. Tra gli altri candidati, Morra ha ingannato te e Morra per me .

Questa è una classe completa che implementa l' Playerinterfaccia. Spiegazione di seguito.

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 };
    }
}

Spiegazione

Ho iniziato analizzando i giochi con un minor numero di dita. Il più semplice non banale consente le chiamate 0o 1e ha la seguente tabella di payoff (i valori sono payoff per il giocatore di riga):

       (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

La (0,0)strategia è dominata da (0,1), quindi possiamo ridurre il tavolo a

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

Ora la (1,0)strategia è dominata da (0,1), quindi possiamo ridurre ulteriormente la tabella

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

E ora (1,1)è dominato da (0,1), quindi finiamo con

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

Perciò giocare sempre (0,1)è un equilibrio di Nash. Ma la cosa curiosa è che non è l'unico. Questo è un gioco simmetrico a somma zero, quindi il payoff atteso è 0, e qualsiasi strategia mista combinata (0,1)e (1,0)dove (0,1)viene scelta almeno il 50% delle volte raggiunge quel payoff. Quindi abbiamo uno spazio monodimensionale di equilibri di Nash.

Sembra essere il caso, anche se non l'ho provato, che il ndito Morra ha un politipo ntridimensionale di equilibri di Nash che sono strategie miste tra le n+1 (pick, guess)coppie per le quali pick + guess = n.

I numeri magici nel codice sopra codificano i 32 vertici del politopo 5-dimensionale degli equilibri di Nash. Li ho trovati impostando un'istanza di programmazione lineare che rappresentava il polytope e quindi usando funzioni di obiettivo casuali. Il motivo per codificare tutti e 32 piuttosto che sceglierne uno è semplice: il payoff previsto è 0, quindi devo fare meglio del previsto per ottenere una vittoria. In sostanza, suppongo che l'altro giocatore stia usando una strategia mista e stimare la distribuzione in base alla cronologia delle selezioni. Quindi seleziono il vertice del politopo che massimizza il mio guadagno previsto rispetto a quella distribuzione stimata.

QuinnAndValor dimostra la vulnerabilità del presupposto che l'altro giocatore stia usando una strategia mista. Rilevando un giocatore che utilizza le strategie dagli equilibri di Nash è in grado di passare a una modalità di camminata casuale in cui, giocando una strategia di non equilibrio, è in media responsabile di perdere, ma deve solo guadagnare un vantaggio una volta e poi può tornare a giocare coppie per le quali pick + guess = n. Quindi gli equilibri di Nash per un singolo gioco non si generalizzano banalmente agli equilibri di Nash per il gioco ripetuto, il che consente strategie più complesse.


4
È possibile che la tua magia contenga una parte dei numeri di Hamming ? Certamente non li contiene tutti, ma molti ( o tutti? ) Sono nell'elenco di quel sito web.
GiantTree,

@GiantTree, sono tutti numeri di Hamming. Osservazione interessante
Peter Taylor,

Non c'è da stupirsi che il tuo robot stia andando male. : D
mbomb007,

11

Quinn and Valor (aggiornato)

Quinn e Valor sono una squadra di ranger d'élite. Con balestra e artiglio, lacerano ogni avversario osa sfidarlo.

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();
        }
    }
}

Vincono quasi sempre contro tutta la soluzione Java sulla mia macchina.

Modificare:

Ammetto che Quinn e Valor non sono riusciti a duellare lo storico, ma ho ancora buona fiducia in loro per vincere il torneo.

Il mio principio è, per qualsiasi soluzione con choice + guess == 5, anche giocare con i choice + guess == 5beneficiari mantenendo il tuo vantaggio.

Aggiornare:

Bene ... tutto è diventato complicato.


1
Mi piace il riferimento di League of Legends. Voglio davvero fare un bot Teemo ora. :)
mbomb007,

6

Studioso

Scholar cerca di imparare dalle mosse del suo avversario, scegliendo quello che il suo avversario ha indovinato meno e indovinando quello che il suo avversario ha usato di più. Ma la teoria non è tutto, quindi Scholar non va molto bene ...

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 };
        }   
    }
}

6

DeltaMAX

(Aggiornato per non utilizzare i file e aggiunta una nuova sezione. Anche modificato per non rimanere più bloccato nella prima sezione.)

Consiste in un paio di strategie che iniziano in modo semplice, poi diventano più complesse: se ne elimini una, passa alla sezione successiva.

  • Sezione 1: Indovina {0, 5}costantemente
  • Sezione 2: controlla se le tue ultime 4 ipotesi formano un modello costante, lineare o quadratico e continua a indovinare il modello fino a quando non si rompe
  • Sezione 3: Verifica se indovina una quantità anormalmente bassa di un numero (inferiore a 1/13) e scegli quel numero
  • Sezione 4: analizza i bigram nelle tue scelte e guarda cosa è più probabile che venga fuori dopo
  • Sezione 5: guarda gli ultimi 100 round e scegli la (choice, guess)coppia che avrebbe le migliori aspettative, ponderata in modo che gli ultimi round siano più importanti
  • Sezione finale: indovina a caso, con una maggiore probabilità di avere scelte basse e ipotesi alte. Se arrivi qui, DeltaMax ha rinunciato e vorrebbe dire "buon gioco".

Per scoprire quale strat è stato usato alla fine, decommenta il file

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

linea.

Mi scuso per l'orrido Java, ho trascorso il pomeriggio a mettere insieme i pezzi e ad imparare di nuovo la lingua :)

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};
    }
}

Con l'attuale implementazione del controller, non è necessario salvare le cose in un file se i dati vengono utilizzati solo per un singolo gioco. cioè private int strat;è abbastanza buono.
johnchen902,

@ johnchen902 Grazie, non mi ero reso conto di poterlo fare. Questo rende le cose molto più facili.
Sp3000,

6

Storico

(Aggiornato: stessa logica, codice più breve e 100 volte più veloce ma puoi usare solo un bot Historian in un torneo.)

Usa una ponderazione casuale per scegliere una coppia ipotetica basata sull'efficacia dell'uso di quella coppia contro la storia precedente degli avversari. I pesi sono i quadrati dei punteggi ottenibili.

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};} }

Batte Quinn and Valor (non più) e perde Morra Cowbell. Nel torneo con la maggior parte dei robot Historianarriva secondo Quinn and Valor.


Bene, è bello vedere che ho vinto sulla macchina di qualcuno. Sto perdendo l'attuale classifica ufficiale . Mi chiedevo fosse per sfortuna o qualche insetto sottile imprevisto.
johnchen902,

@ johnchen902 Devo avere battiti allucinati Morra Cowbell. Ha modificato il post. Puoi eliminare i commenti se diventano obsoleti.
randomra,

Penso di poter vincere il 75% del nostro duello ora dopo il mio aggiornamento!
johnchen902,

5

Extrapolator (v1.1)

Estrapolazione estrema da uno degli equilibri di Nash di un gioco più semplice.

Sostengo il formato di risposta conciso! (In stile pitone.)

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}; } }

Sembra legare con la mucca magica (Morra Cowbell) e batte altre voci che ho controllato.


1
Sposta la R casuale in un campo statico, in modo da non inizializzarla ogni volta, questo aiuterà le prestazioni complessive!
Falco,

Perché il cambiamento nella distribuzione?
Peter Taylor,

4

Di moda

Trendy dà un'occhiata alle mosse passate dell'avversario, ponderandole per recency. Indovina il più pesante e ne prende uno spostato leggermente da quello. Eccolo, in tutta la sua gloria:

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};}}    

L'unica cosa con cui posso confrontarlo ora è Cowbell. Perde per un piccolo margine la maggior parte delle volte, ma esce spesso abbastanza per i miei gusti. Vedremo come va con più concorrenti.


7
Potresti per favore formattare il codice su più righe? Questo non è un codice golf ...
mbomb007,

7
@ mbomb007 Occupa meno spazio in questo modo. Uno dei dolori di KotHs in generale è tutto lo scorrimento per guardare le voci. Ho descritto cosa fa ed è molto semplice formattare le parti interessate.
Geobits l'

4

Indovina casuale

Questo è davvero semplice. Lancia effettivamente un d6 e aggiunge un altro tiro al tiro precedente per indovinare. Non vincerà, ma fornirà un buon punto di riferimento.

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) };
    }
}

4

Confuso, Python 3

Una voce inutilmente complicata. Anche io non so cosa faccia.

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))

Anche se questo algoritmo avanzato sembra avere prestazioni peggiori rispetto a quelle casuali in questo torneo e utilizza una memoria e un tempo di esecuzione significativi, ha risultati sorprendenti per determinati valori di 5 ;-)


4

Rainbolt

Prende la differenza tra gli ultimi due numeri indovinati dal nostro avversario, aggiunge quello all'ultima ipotesi del nostro avversario, trova il modulo ed evita di scegliere quel numero a tutti i costi. Ad esempio, se indovini {5,4,3} (diminuendo di uno), eviteremmo di sceglierne 2 a tutti i costi.

Prende la differenza tra gli ultimi due numeri scelti dal nostro avversario, aggiunge quello all'ultima scelta del nostro avversario e indovina quel numero. Ad esempio, se indovini {1,4,5,2} (aumentando di tre) indovineremo 5.

Evita inutili o molto vicini ai rulli inutili.

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);
    }
}

Non rendere getMove()statico il tuo metodo. Non è possibile implementare un metodo non statico come quello (almeno non in Java 8).
GiantTree,

@GiantTree Grazie per averlo colto.
Rainbolt,

3

Bot evoluto

Ho evoluto questo bot per essere il miglior robot basato su casuale.

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);
    }

}

3

Popolarità, Python 3

Calcola ipotesi in base ai numeri popolari utilizzati in passato dall'avversario. I numeri utilizzati di recente hanno un peso maggiore. La scelta del numero è spesso la stessa dell'ipotesi.

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))

3

interpolator

(Passato a Java poiché Python stava causando problemi)

Utilizza l'interpolazione polinomiale sulle ultime 10 scelte dell'avversario per calcolare il numero successivo dell'avversario, quindi fa lo stesso per le proprie scelte ed evita di scegliere quel numero. Inoltre, Interpolator ha una leggera propensione a scegliere 0 o 5 e la sua scelta è talvolta influenzata dalla sua ipotesi:

  • Se indovina 0 non sceglierà mai 0
  • Se indovina 5 sceglierà sempre 0 o 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};
    }
}

3

CounterBot

Non neutralizza nessuno, ma conta invece attraverso 0-5 in un cerchio ( 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
    }
}

2

Basilisco, Python

Secondo la leggenda, Il Basilisco è il re dei serpenti. ( fonte ) Ho pensato che fosse un nome appropriato per un bot che suonava "The Noble Game Of Kings" ed è scritto in pitone. = D Questo robot colpisce la paura nel cuore degli altri robot e provoca la morte con un solo sguardo.

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)

Funziona con una strategia piuttosto semplice. Non mi aspetto che vinca, ma è stato divertente scrivere. Questa è anche la mia prima sfida KoTH, quindi sono entusiasta di vedere come si comporta bene.

Come sceglie la sua prossima mossa.

Il Basilisco fa sempre la mossa che il suo avversario ha indovinato il minor numero di volte. In caso di pareggio, sceglierà il numero più piccolo. (per ridurre al minimo il numero di punti degli avversari.)

Come sceglie la sua prossima ipotesi.

Il Basilisco sceglierà la risposta più probabile alla sua ipotesi precedente. Ad esempio, se l'ultima volta ha indovinato un 3, ripercorrerà tutte le volte precedenti che ha indovinato un 3, quindi restituirà la mossa dell'avversario più comune che viene dopo un'ipotesi di 3. In caso di pareggio , sceglierà il numero più grande (per massimizzare il numero di punti che potrebbe guadagnare).

Su una nota tecnica, questo funzionerà correttamente? Print () è sufficiente o dovrei usare qualcosa come sys.stdout.write () come hanno fatto gli altri Pythonistas?


sys.stdout.write () funziona in entrambi i Python. print () funziona solo in Python 3. Tuttavia, dovrebbe essere a posto.
TheNumberOne

No, print () funziona in entrambi i casi, ne sono sicuro. Le parentesi sono opzionali in 2.x
DJMcMayhem

In base a ciò , funzionano in modo diverso. Tuttavia, il modo in cui lo usi, non importa.
TheNumberOne

Ma fa qualche differenza?
DJMcMayhem

Apparentemente no.
TheNumberOne

2

Idem

Questo si trasforma nell'avversario, ma dietro di una supposizione / scelta.

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;
    }
}

1

NullifierBot, Java

Lancia sempre 0 per ridurre al minimo qualsiasi vincita dell'avversario. Se l'avversario indovina il mio numero, guadagna solo ciò che ha lanciato.

Indovina sempre 5 per massimizzare le mie vincite. Dal momento che non riesco a ottenere punti dal mio tiro, voglio ottenere altrettanti dall'avversario. Potrei indovinare a caso, ma dov'è il divertimento?

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}; 
    }
}

Immagino che questo bot farà terribilmente. Qualsiasi bot che utilizza le probabilità potrebbe persino ottenere ogni singola ipotesi subito dopo il primo.
mbomb007,

@ mbomb007 Non è il peggiore, però! Anche se funziona peggio del tuo RandomBot.
Brian J,

1

Erratica, Java

Non eccezionale, ma è stato originariamente progettato per essere per lo più casuale, fino a quando il valore del compromesso non è emerso da me. Riesce a perdere costantemente contro 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;
    }
}

1

Eco, 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]

Gioca l'ultimo gioco fatto dall'avversario, sulla base della teoria che chiunque può creare un bot che non può prevedere. Indovina in base al valore di aspettativa usando un campione di cento mosse.


Ricevo questo errore: echo.rb:3:in <main> ': metodo non definito size' for nil:NilClass (NoMethodError). Sembra accadere solo al primo turno, quando non c'è la cronologia delle mosse.
PhiNotPi,

Strano, non è successo quando ho provato. Lo modificherò.
istocrato,

Qual è la rilevanza della if (mychoices.size > 990 && myscore == '0') nextchoice = rand(1..5)parte?
randomra,

Se sta per finire in un pareggio senza punteggio (come accadrebbe, ad esempio, contro se stesso), inizia a giocare in modo casuale, poiché il 50% di probabilità di vincere è meglio di niente.
istocratico,

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}; 

    }
}

Questo ragazzo consiste in cattivi algoritmi di ipotesi che usano per lo più array ponderati.


Sarà nel prossimo aggiornamento.
PhiNotPi,

1

Uh So cosa stai pensando. "Ne sceglierà cinque o qualcos'altro?" Beh, a dirti la verità in tutta questa eccitazione non sono sicuro di me stesso, ma essendo questo è un metodo .44, il metodo più potente del mondo e sovraccaricheresti subito il tuo stack, devi farti una domanda : "Mi sento fortunato?"

Bene, punk?

public class DirtyHarry implements Player {

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

    @Override
    public int[] getMove(String[] args) {
        return new int[]{5, 5};
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.