Morra, das edle Spiel der Könige


28

Hintergrund

Das Spiel Morra ist ein einfaches Spiel. In der "Original" -Version werfen mehrere Spieler gleichzeitig eine Zahl von 0 bis 5 mit ihren Händen aus, während sie die Gesamtsumme aller Hände erraten. Die hier verwendete Version wurde geändert, um das Potenzial für nicht-triviale Strategien zu erhöhen. Sie wird nachfolgend beschrieben:

  • Es gibt zwei Spieler.
  • Wie bei einer Stein-Papier-Schere bewegen sich die Spieler gleichzeitig.
  • In jeder Runde wählt jeder Spieler eine Zahl von 0-5 und errät auch die Wahl seines Gegners von 0-5. Dies bedeutet, dass jede Runde zwei Zahlen ausgegeben werden. Zur Verdeutlichung sollte die Ausgabe beider Zahlen im Bereich von 0 bis einschließlich 5 liegen.
  • Wenn Sie die Wahl Ihres Gegners richtig erraten, aber Ihr Gegner nicht richtig geraten hat, gewinnen Sie eine bestimmte Anzahl von Punkten, die der Summe der beiden gespielten Zahlen entspricht. Wenn zum Beispiel die gespielten Zahlen 3 und 5 wären, wäre eine korrekte Schätzung 8 Punkte wert.
  • Wenn beide oder keiner der Spieler richtig raten, werden keine Punkte vergeben.
  • Die Person mit den meisten Punkten nach 1000 Runden gewinnt das Spiel.

Der Wettbewerb

Das Turnier wird im Round-Robin-Stil ausgetragen und es wird jede mögliche Paarung von Teilnehmern erstellt. Für jeden Sieg erhält der Teilnehmer 2 Siegpunkte. Jedes Unentschieden ergibt 1 Siegpunkt. Für einen Verlust werden keine Siegpunkte gewonnen.

Intuitiv ist der Gewinner des Turniers der Teilnehmer mit den meisten Siegpunkten gegen andere.


Wie betrete ich?

Es gibt zwei Methoden, um Bots zum Wettbewerb einzureichen. Die erste und am meisten bevorzugte Methode besteht darin, eine vom Controller bereitgestellte Java-Schnittstelle zu implementieren. Die zweite Methode besteht darin, ein unabhängiges Programm zu schreiben.

Lassen Sie uns zuerst die Java-Methode behandeln. Die Schnittstelle, die Sie implementieren müssen, ist Playerund definiert zwei Methoden: public String getName()Identifiziert Ihren Bot und public int[] getMove(String[] args)nimmt argsals Array von sechs Zeichenfolgen mychoices myguesses myscore opponentchoices opponentguesses opponentscore. Ein Beispiel ist das folgende:

042 045 0 324 432 6

Dies bedeutet, dass ich in der ersten Runde 0 gewählt und vermutet habe, dass mein Gegner eine 0 werfen würde. Mein Gegner hat eine 3 geworfen und ich habe eine 4 geworfen. In der dritten Runde hat mein Gegner die richtige Vermutung gemacht, dass ich werfen würde eine 2, was bedeutet, dass er 2 + 4 = 6 Punkte gewinnt.

Ihre Methode gibt ein Array mit zwei Ganzzahlen zurück, die Sie auswählen bzw. schätzen. Ein Beispiel ist {4,2}für eine Auswahl von 4 und eine Vermutung von 2.

Hier ist ein Beispiel für einen vollständigen Java-Bot, der als Methode geschrieben wurde. Wenn Sie möchten, muss Ihre Einreichung nur enthalten, was in der getMoveMethode vor sich geht.

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

Als eigenständiges Programm

Ich kann derzeit nur begrenzt weitere Sprachen unterstützen. Neben Java kann ich auch Programme akzeptieren, die in Python 3.4, Perl 5 oder Ruby 2.1.5 geschrieben wurden. Wenn es eine Sprache gibt, die mehrere Leute zu wollen scheinen, werde ich mein Bestes tun, um sie hinzuzufügen.

Die Eingabe in Ihr Programm erfolgt über Argumente in der Befehlszeile. Es könnte so aussehen:

perl awesomebot.plx 042 045 0 324 432 6

Die Ausgabe Ihres Programms sollte Ihre Wahl sein, gefolgt von Ihrer Vermutung, gefolgt von Leerzeichen.

Bitte geben Sie in Ihrer Antwort den genauen Befehl an, der zum Ausführen erforderlich ist. Denken Sie daran, dass ich Windows 8.1 verwende.


Extra Regeln

Status und Zeitüberschreitungen werden gespeichert

Ihr Programm darf eine Textdatei im lokalen Verzeichnis erstellen, in der Sie Informationen speichern können. Diese Informationen werden während des gesamten Turniers gespeichert, aber anschließend gelöscht. Geben Sie der Datei einen Namen, den ich identifizieren kann.

Es gibt ein Zeitlimit von 500 Millisekunden, bis Ihr Code antwortet. Wenn Sie nicht innerhalb der vorgegebenen Frist antworten (oder einen ungültigen Zug ausführen), verfällt das jeweilige Spiel. Java-Übermittlungen haben derzeit eine passive Zeitüberschreitung (die ich möglicherweise auf aktive aktualisieren möchte), wohingegen Nicht-Java-Übermittlungen eine aktive Zeitüberschreitung aufweisen, bei der ihr Prozess nach 500 Millisekunden beendet wird.

Weitere Einreichungsregeln

  • Sie können mehrere Beiträge einreichen, sofern diese den Regeln entsprechen und kein Tag-Team bilden.
  • Jeder Eintrag muss eindeutig sein. Sie können keine exakte Kopie der Logik eines anderen Bots in einer anderen Sprache erstellen.
  • Die Bots können nicht miteinander interagieren (um ein Team zu bilden).
  • Sie können die Logik der anderen Bots in Ihrem Bot nicht verwenden, um beispielsweise Ihren Konkurrenten zu identifizieren und dessen Aktionen vorherzusagen. Sie können natürlich versuchen, die Strategie Ihres Gegners zu bestimmen.
  • Versuchen Sie nicht, mit dem Controller, anderen Teilnehmern oder meinem Computer in Konflikt zu geraten. Stellen Sie keine Verbindung zu externen Informationsquellen her.

Der Controller

Die aktuelle Version des Controllers finden Sie hier . Es ist in Java 8 geschrieben. Die "Tournament" -Datei ist der Haupt-Controller, der auch die Liste der Teilnehmer enthält (wenn Sie Ihre eigenen Wettbewerbe veranstalten möchten).


Bestenliste

Ich konnte die Bestenliste nicht sehr oft aktualisieren. Ich bin dieses Wochenende ziemlich beschäftigt. Mit "ziemlich beschäftigt" meine ich, dass von 6.30 bis 21.30 Uhr kein Zugriff auf einen Computer möglich ist. Hier sind die Ergebnisse nach 5 Läufen. Der "Echo" -Bot verfiel aus irgendeinem Grund (könnte meine Schuld sein, die ich noch nicht untersucht habe).

  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          

Kredit

Vielen Dank an Rainbolt und Peter Taylor für ihre Hilfe beim Controller.


1
@ MartinBüttner Ruby 2.1.5 wurde hinzugefügt.
PhiNotPi

Wie funktioniert das Round Robin? Spieler1 gegen Spieler2 1000-mal, Spieler1 gegen Spieler3 1000-mal usw. ... ODER ist es Spieler1 gegen Spieler2 einmal, dann Spieler1 gegen Spieler 3 einmal usw. ...
Vajura

@Vajura Ein einzelnes Turnier besteht aus 1 Kampf zwischen jedem Paar. Eine Schlacht hat 1000 Runden, wobei die höchste Gesamtpunktzahl am Ende der Schlacht darüber entscheidet, wer die beiden Siegpunkte erhält. Das aktuelle Scoreboard zeigt die Gesamtsiegpunkte nach 40 Turnieren.
PhiNotPi

Entschuldigen Sie die Verzögerungen bei der Aktualisierung des Boards. Ich bin dieses Wochenende sehr beschäftigt. Erwarten und aktualisieren Sie heute Abend und morgen früh.
PhiNotPi

Wow, ich habe nicht erwartet, dass mein Bot so gut abschneidet! Was bedeuten die Zahlen für die erste Ergebnismenge ... Anzahl der Siege?
mbomb007

Antworten:


17

Morra Cowbell

Für jeden, der nach Bedeutung im Namen dieses Bots sucht, lässt der Name Morra mich an Space Italian denken , also habe ich geglaubt, ich brauche einen Namen, der darauf spielt. Andere Kandidaten, darunter Morra, täuschen dich und Morra für mich .

Dies ist eine vollständige Klasse, die die PlayerSchnittstelle implementiert . Erklärung unten.

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

Erläuterung

Ich begann damit, Spiele mit weniger Fingern zu analysieren. Das einfachste nicht-triviale erlaubt Anrufe von 0oder 1und hat die folgende Auszahlungstabelle (Werte sind Auszahlungen für den Reihenspieler):

       (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

Die (0,0)Strategie wird von dominiert (0,1), sodass wir den Tisch auf reduzieren können

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

Jetzt wird die (1,0)Strategie von dominiert (0,1), so dass wir den Tisch weiter reduzieren können

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

Und jetzt (1,1)wird dominiert (0,1), also landen wir bei

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

Deshalb ist das Spielen (0,1)immer ein Nash-Gleichgewicht. Aber das Merkwürdige ist, dass es nicht der einzige ist. Dies ist ein symmetrisches Nullsummenspiel, so dass die erwartete Auszahlung 0 ist, und jede gemischte Strategie kombinieren (0,1)und in (1,0)der (0,1)mindestens 50% der Zeit , die Auszahlung gepflückt erreicht. Wir haben also einen eindimensionalen Raum von Nash-Gleichgewichten.

Es scheint der Fall zu sein, obwohl ich es nicht bewiesen habe, dass n-Finger-Morra ein neindimensionales Polytop von Nash-Gleichgewichten hat, die gemischte Strategien zwischen den n+1 (pick, guess)Paaren sind, für die pick + guess = n.

Die magischen Zahlen im obigen Code codieren die 32 Eckpunkte des 5-dimensionalen Polytops des Nash-Gleichgewichts. Ich fand sie, indem ich eine lineare Programmierinstanz aufbaute, die das Polytop darstellte, und dann zufällige Zielfunktionen verwendete. Der Grund, alle 32 zu codieren, anstatt einen auszuwählen, ist einfach: Die erwartete Auszahlung ist 0, also muss ich es besser machen als erwartet, um einen Gewinn zu erzielen. Ich gehe im Wesentlichen davon aus, dass der andere Spieler eine gemischte Strategie verwendet, und schätze die Verteilung basierend auf seiner Auswahlhistorie. Dann wähle ich den Polytop-Vertex aus, der meinen erwarteten Gewinn gegenüber dieser geschätzten Verteilung maximiert.

QuinnAndValor demonstriert die Verwundbarkeit der Annahme, dass der andere Spieler eine gemischte Strategie verwendet. Durch das Erkennen eines Spielers, der die Strategien aus den Nash-Gleichgewichten verwendet, kann er in einen Zufallsmodus wechseln, in dem er bei einer Nicht-Gleichgewichtsstrategie im Durchschnitt verlieren kann, aber nur einmal einen Vorsprung aufbauen muss es kann auf das Spielen von Paaren zurückgreifen, für die pick + guess = n. Die Nash-Gleichgewichte für ein einzelnes Spiel lassen sich daher nicht einfach auf die Nash-Gleichgewichte für das wiederholte Spiel übertragen, was komplexere Strategien ermöglicht.


4
Ist es möglich, dass Ihre Magie einen Teil der Hamming-Nummern enthält ? Es enthält sicherlich nicht alle, aber viele ( oder alle? ) Von ihnen sind in der Liste auf dieser Website.
GiantTree

@GiantTree, das sind alles Hamming-Nummern. Interessante Beobachtung.
Peter Taylor

Kein Wunder, dass dein Bot Schinken geht. : D
mbomb007

11

Quinn and Valor (aktualisiert)

Quinn und Valor sind ein Elite-Rangerteam. Mit Armbrust und Klaue zerreißen sie jeden Gegner, der es wagt, sie herauszufordern.

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

Sie gewinnen fast immer gegen alle Java-Lösungen auf meinem Computer.

Bearbeiten:

Ich gebe zu, dass Quinn und Valor es nicht geschafft haben, sich mit Historian zu duellieren, aber ich habe immer noch guten Glauben daran, dass sie das Turnier gewinnen werden.

Mein Prinzip ist, für jede Lösung mit choice + guess == 5, auch mit choice + guess == 5Stipendiaten zu spielen, um Ihren Vorteil zu bewahren.

Aktualisieren:

Nun ... alles ist gerade kompliziert geworden.


1
Ich mag die League of Legends Referenz. Ich möchte jetzt wirklich einen Teemo-Bot machen. :)
mbomb007

6

Gelehrte

Der Gelehrte versucht, aus den Bewegungen seines Gegners zu lernen, indem er diejenige auswählt, die sein Gegner weniger vermutet und diejenige, die sein Gegner am häufigsten benutzt. Aber Theorie ist nicht alles, deshalb macht der Gelehrte es nicht besonders gut ...

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

(Aktualisiert, um keine Dateien zu verwenden, und neuer Abschnitt hinzugefügt. Auch geändert, um im ersten Abschnitt nicht mehr hängen zu bleiben.)

Besteht aus einigen Strategien, die einfach beginnen und dann komplexer werden. Wenn Sie eine Strategie löschen, gelangen Sie zum nächsten Abschnitt.

  • Abschnitt 1:{0, 5} Beständig raten
  • Abschnitt 2: Überprüfen Sie, ob Ihre letzten 4 Vermutungen ein konstantes, lineares oder quadratisches Muster ergeben, und schätzen Sie das Muster so lange, bis es bricht
  • Abschnitt 3: Überprüfen Sie, ob Sie eine ungewöhnlich geringe Anzahl (weniger als 1/13) erraten, und wählen Sie diese Anzahl aus
  • Abschnitt 4: Analysieren Sie Bigramme in Ihren Entscheidungen und schauen Sie sich an, was als nächstes wahrscheinlicher herauskommt
  • Abschnitt 5: Schauen Sie sich die letzten 100 Runden an und wählen Sie das (choice, guess)Paar aus, das die beste Erwartung hat, gewichtet, damit die letzten Runden wichtiger sind
  • Abschnittsende: Vermutung zufällig, mit höherer Wahrscheinlichkeit, geringe Auswahl und hohe Vermutungen zu haben. Wenn Sie hierher kommen, hat DeltaMax aufgegeben und möchte sagen, "gutes Spiel".

Um herauszufinden, welche Schicht am Ende verwendet wurde, entfernen Sie das Kommentarzeichen

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

Linie.

Entschuldigung für das schreckliche Java, ich habe meinen Nachmittag damit verbracht, Teile zusammenzusetzen und die Sprache neu zu lernen :)

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

Mit der aktuellen Implementierung von Controller müssen keine Dinge in einer Datei gespeichert werden, wenn die Daten nur für ein einzelnes Spiel verwendet werden. dh private int strat;ist gut genug.
johnchen902

@ johnchen902 Danke, mir war nicht klar, dass ich das schaffen könnte. Das macht die Sache viel einfacher.
Sp3000,

6

Historiker

(Aktualisiert: gleiche Logik, kürzerer Code und 100-mal schneller, aber Sie können nur einen Historian-Bot bei einem Turnier verwenden.)

Verwendet den gewichteten Zufall, um ein Wurfschätzungspaar zu wählen, basierend auf der Effektivität, dass nur dieses Paar gegen den vorherigen Verlauf des Gegners verwendet wird. Die Gewichte sind die Quadrate der erreichbaren Punkte.

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

Schlägt Quinn and Valor (nicht mehr) und verliert gegen Morra Cowbell. Im Turnier mit den meisten Bots Historiansteht der zweite Platz an Quinn and Valor.


Es ist schön zu sehen, dass ich auf einer Maschine gewonnen habe. Ich verliere die aktuelle offizielle Rangliste. Ich habe mich gefragt, ob es das Pech oder ein unvorhergesehener kleiner Fehler ist.
johnchen902

@ johnchen902 Ich muss das Schlagen halluziniert haben Morra Cowbell. Hat den Beitrag bearbeitet. Sie können Kommentare jedoch löschen, wenn sie veraltet sind.
Randomra

Ich denke, ich kann jetzt nach meinem Update 75% unseres Duells gewinnen!
johnchen902

5

Extrapolator (v1.1)

Extreme Extrapolation aus einem der Nash-Gleichgewichte eines einfacheren Spiels.

Ich unterstütze das knappe Antwortformat! (Im Python-Stil.)

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

Scheint mit der Magic Cow (Morra Cowbell) zu binden und schlägt andere Einträge, die ich überprüft habe.


1
Bitte verschieben Sie das Zufällige r in ein statisches Feld, damit es nicht jedes Mal initialisiert wird. Dies trägt zur allgemeinen Leistung bei!
Falco,

Warum die Umverteilung?
Peter Taylor

4

Modisch

Trendy wirft einen Blick auf die vergangenen Züge des Gegners und gewichtet sie nach Aktualität. Vermutet den schwersten und nimmt einen davon leicht ab. Hier ist es in seiner ganzen Pracht:

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

Das einzige, womit ich es jetzt vergleichen kann, ist Cowbell. Es verliert die meiste Zeit mit einem kleinen Vorsprung, liegt aber für meinen Geschmack oft genug vorne. Wir werden sehen, wie es mit mehr Wettbewerbern aussieht.


7
Könnten Sie bitte den Code auf mehrere Zeilen formatieren? Dies ist kein Code Golf ...
mbomb007

7
@ mbomb007 Auf diese Weise wird weniger Platz benötigt. Eines der Probleme von KotHs im Allgemeinen ist das Scrollen, um Einträge zu betrachten. Ich habe beschrieben, was es tut, und es ist für interessierte Parteien sehr einfach, es zu formatieren.
Geobits

4

Zufälliger Guesser

Das ist wirklich unkompliziert. Es würfelt effektiv einen W6 und fügt dem vorherigen Wurf einen weiteren Wurf hinzu. Es wird nicht gewinnen, aber es wird ein guter Maßstab sein.

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

Verwirrt, Python 3

Ein unnötig komplizierter Eintrag. Auch ich weiß nicht, was es tut.

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

Obwohl dieser fortschrittliche Algorithmus in diesem Turnier schlechter als zufällig zu sein scheint und viel Speicher und Laufzeit benötigt, liefert er für bestimmte Werte von 5 erstaunliche Ergebnisse ;-)


4

Regenblitz

Nimmt den Unterschied zwischen den letzten beiden Zahlen, die unser Gegner erraten hat, addiert dies zu den neuesten Schätzungen unseres Gegners, findet den Modul und vermeidet es, diese Zahl um jeden Preis zu wählen. Wenn Sie beispielsweise {5,4,3} schätzen (absteigend um eins), vermeiden wir unter allen Umständen die Auswahl von 2.

Nimmt den Unterschied zwischen den letzten beiden Zahlen, die unser Gegner gewählt hat, addiert dies zu der letzten Wahl unseres Gegners und schätzt diese Zahl. Wenn Sie beispielsweise {1,4,5,2} schätzen (um drei erhöhen), würden wir 5 schätzen.

Vermeidet sinnlose oder sehr nahe an sinnlosen Rollen.

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

Machen Sie Ihre getMove()Methode nicht statisch. Sie können eine solche nicht statische Methode nicht implementieren (zumindest nicht in Java 8).
GiantTree

@GiantTree Danke, dass du das erwischt hast.
Rainbolt

3

Entwickelter Bot

Ich habe diesen Bot zum besten zufallsbasierten Bot entwickelt.

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

Popularität, Python 3

Berechnen Sie die Schätzung anhand der in der Vergangenheit vom Gegner verwendeten populären Zahlen. Die zuletzt verwendeten Zahlen haben mehr Gewicht. Die Wahl der Zahl ist oft die gleiche wie die Vermutung.

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

(Wurde auf Java umgestellt, da Python Probleme verursachte.)

Verwendet die Polynominterpolation für die letzten 10 Gegnerwahlen, um die nächste Zahl des Gegners zu ermitteln, und tut dann dasselbe mit seinen eigenen Wahlen und vermeidet es , diese Zahl zu wählen. Interpolator hat auch eine leichte Abneigung gegen die Wahl von 0 oder 5, und seine Wahl wird manchmal durch seine Vermutung beeinflusst:

  • Wenn es 0 errät, wird es niemals 0 wählen
  • Wenn es 5 errät, wählt es immer 0 oder 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

Nicht Zähler jemand , sondern zählt durch 0-5 in einem Kreis ( 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

Basilisk, Python

Der Legende nach ist der Basilisk der König der Schlangen. ( Quelle ) Ich dachte, das ist ein passender Name für einen Bot, der "The Noble Game Of Kings" spielt und in Python geschrieben ist. = D Dieser Bot schlägt Furcht in das Herz der anderen Bots und verursacht den Tod mit einem einzigen Blick.

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)

Dies läuft auf einer ziemlich einfachen Strategie. Ich erwarte nicht, dass es gewinnt, aber es hat Spaß gemacht zu schreiben. Dies ist auch meine erste KoTH-Herausforderung. Ich bin gespannt, wie gut sie abschneidet.

Wie es seinen nächsten Schritt auswählt.

Der Basilisk macht immer den Zug, den sein Gegner am wenigsten erraten hat. Im Falle eines Unentschieden wählt er die kleinere Zahl. (um die Anzahl der Punkte des Gegners zu minimieren.)

Wie es seine nächste Vermutung trifft.

Der Basilisk wird die wahrscheinlichste Antwort auf seine vorherige Vermutung auswählen. Wenn es zum Beispiel das letzte Mal eine 3 erraten hat, wird es alle vorherigen Male durchlaufen, bei denen es eine 3 erraten hat, und dann den häufigsten gegnerischen Zug zurückgeben, der nach einer Vermutung von 3 eintritt , wählt es die größere Zahl (um die Anzahl der Punkte zu maximieren, die es machen könnte.)

Läuft dies technisch gesehen korrekt? Ist print () ausreichend, oder sollte ich so etwas wie sys.stdout.write () verwenden, wie es die anderen Pythonisten getan haben?


sys.stdout.write () funktioniert in beiden Python-Versionen. print () funktioniert nur in Python 3. Es sollte aber in Ordnung sein.
TheNumberOne

Nein, print () funktioniert auch, da bin ich mir sicher. Klammern sind in 2.x optional
DJMcMayhem

Nach dieser , sie funktionieren anders. Es spielt jedoch keine Rolle, wie Sie es verwenden.
TheNumberOne

Aber macht das einen Unterschied?
DJMcMayhem

Scheinbar nicht.
TheNumberOne

2

Dito

Dies verwandelt sich in den Gegner, aber hinterher durch eine Vermutung / Wahl.

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

Wirft immer 0, um die Gewinne des Gegners zu minimieren. Wenn der Gegner jemals meine Nummer errät, verdient er nur das, was er geworfen hat.

Errate immer 5, um meine Gewinne zu maximieren. Da ich mit meinem Wurf keine Punkte erzielen kann, möchte ich möglichst viele vom Gegner erhalten. Ich könnte zufällig raten, aber wo ist der Spaß dabei?

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

Ich vermute, dass dieser Bot schrecklich tun wird. Jeder Bot, der Odds nutzt, wird vielleicht sogar jede einzelne Vermutung direkt nach der ersten bekommen.
mbomb007

@ mbomb007 Es ist jedoch nicht das Schlimmste! Obwohl es schlechter abschneidet als Ihr RandomBot.
Brian J

1

Erratica, Java

Nicht großartig, aber es war ursprünglich so konzipiert, dass es größtenteils zufällig war, bis der Wert des Kompromisses bei mir herausfiel. Schafft es, konstant gegen Counter Bot> _ <zu verlieren

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

Echo, Rubin

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]

Spielt das letzte Spiel des Gegners nach der Theorie, dass jeder einen Bot machen kann, den er nicht vorhersagen kann. Vermutungen basieren auf dem Erwartungswert anhand einer Stichprobe von 100 Zügen.


Ich erhalte den folgenden Fehler: echo.rb:3:in <main> ': undefinierte Methode size' for nil:NilClass (NoMethodError). Es scheint nur in der ersten Runde aufzutreten, wenn es keinen Zugverlauf gibt.
PhiNotPi

Seltsam, ist nicht passiert, als ich getestet habe. Ich werde bearbeiten.
Histokrat

Was ist die Relevanz des if (mychoices.size > 990 && myscore == '0') nextchoice = rand(1..5)Teils?
Randomra

Wenn es zu einem torlosen Unentschieden kommt (wie es zum Beispiel gegen sich selbst der Fall wäre), wird es zufällig gespielt, da eine Gewinnchance von ~ 50% besser ist als nichts.
Histokrat

1

KÖNIG FISCHER

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

    }
}

Dieser Typ besteht aus falschen Alghorithmen, die hauptsächlich gewichtete Arrays verwenden.


Wird im nächsten Update sein.
PhiNotPi

1

Äh äh Ich weiß was du denkst. "Wird er fünf auswählen oder etwas anderes?" Um ehrlich zu sein, bei all dieser Aufregung bin ich mir selbst nicht sicher, aber da dies eine .44-Methode ist, die leistungsstärkste Methode der Welt und Ihren Stack sofort überlasten würde, müssen Sie sich eine Frage stellen : "Fühle ich mich glücklich?"

Na ja, Punk?

public class DirtyHarry implements Player {

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

    @Override
    public int[] getMove(String[] args) {
        return new int[]{5, 5};
    }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.