Morra, le noble jeu des rois


28

Contexte

Le jeu de Morra est un jeu simple. Dans la version "originale", plusieurs joueurs lancent simultanément un numéro 0-5 avec leurs mains tout en devinant la somme totale des mains de chacun. La version que j'utiliserai ici a été modifiée pour augmenter le potentiel de stratégie non triviale, et elle est décrite ci-dessous:

  • Il y a deux joueurs.
  • Comme dans les ciseaux à papier, les joueurs se déplacent simultanément.
  • Chaque tour, chaque joueur choisit un nombre 0-5 et devine également le choix de son adversaire 0-5. Cela signifie que deux nombres sont sortis à chaque tour. Pour clarifier, la sortie des deux nombres doit être comprise entre 0 et 5 inclus.
  • Si vous devinez correctement le choix de votre adversaire mais que votre adversaire n'a pas deviné correctement, vous gagnez un certain nombre de points égal à la somme des deux nombres joués. Par exemple, si les nombres joués étaient 3 et 5, une estimation correcte vaut 8 points.
  • Si les deux joueurs ou aucun des deux ne devine correctement, aucun point n'est attribué.
  • La personne avec le plus de points après 1000 tours remporte la partie.

Le tournois

Le tournoi se déroulera dans un style de tournoi à la ronde et se déroulera en créant chaque paire de concurrents possible. Pour chaque victoire, le candidat gagne 2 points de victoire. Chaque égalité donne 1 point de victoire. Aucun point de victoire n'est gagné pour une perte.

Intuitivement, le vainqueur du tournoi sera le concurrent avec le plus de points de victoire contre les autres.


Comment entrer

Il y aura deux méthodes pour soumettre des robots pour participer. La première méthode, et de loin préférée, consiste à implémenter une interface Java fournie par le contrôleur. La deuxième méthode consiste à écrire un programme indépendant.

Voyons d'abord la méthode Java. L'interface vous devrez implémenter est Playeret il définit deux méthodes: public String getName()identifie votre bot et public int[] getMove(String[] args)prend argscomme un tableau de six cordes, mychoices myguesses myscore opponentchoices opponentguesses opponentscore. Un exemple est le suivant:

042 045 0 324 432 6

Cela signifie que j'ai choisi 0 au premier tour et j'ai deviné que mon adversaire allait lancer un 0. Mon adversaire a lancé un 3 et a deviné que je lancerais un 4. Au troisième tour, mon adversaire a fait la bonne supposition que je lancerais un 2, ce qui signifie qu'il gagne 2 + 4 = 6 points.

Votre méthode renverra un tableau de deux entiers, qui sont respectivement votre choix et votre supposition. Un exemple est {4,2}pour un choix de 4 et une estimation de 2.

Voici un exemple de bot Java complet écrit comme méthode. Si vous le souhaitez, votre soumission doit uniquement inclure ce qui se passe dans la getMoveméthode.

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

En tant que programme indépendant

Je suis actuellement limité dans ma prise en charge de langues supplémentaires. Outre Java, je peux accepter des programmes écrits en Python 3.4, Perl 5 ou Ruby 2.1.5. S'il y a une langue que plusieurs personnes semblent vouloir, je ferai de mon mieux pour l'ajouter.

L'entrée de votre programme sera des arguments sur la ligne de commande. Cela pourrait ressembler à ceci:

perl awesomebot.plx 042 045 0 324 432 6

La sortie de votre programme doit être votre choix suivi de votre supposition, chacun suivi d'un espace.

Veuillez inclure dans votre réponse la commande exacte nécessaire pour l'exécuter. Gardez à l'esprit que j'utilise Windows 8.1.


Règles supplémentaires

Enregistrement de l'état et des délais d'attente

Votre programme sera autorisé à créer un fichier texte dans le répertoire local, où vous pourrez stocker des informations. Ces informations seront conservées tout au long du tournoi mais supprimées par la suite. Donnez au fichier un nom que je peux identifier.

Il y a un délai de 500 millisecondes pour que votre code réponde. Le fait de ne pas répondre dans le délai imparti (ou de donner un coup invalide) entraînera la perte de ce match particulier. Les soumissions Java ont actuellement un délai d'attente passif (que je peux mettre à niveau vers actif), tandis que les soumissions non Java ont un délai d'attente où leur processus se termine après 500 millisecondes.

Plus de règles de soumission

  • Vous êtes autorisé à soumettre plusieurs soumissions, tant qu'elles respectent les règles et ne marquent pas l'équipe.
  • Chaque entrée doit être unique. Vous ne pouvez pas faire une copie exacte de la logique d'un autre bot dans une langue différente.
  • Les bots ne peuvent pas interagir les uns avec les autres (pour former une équipe de toute sorte).
  • Vous ne pouvez pas utiliser la logique des autres robots à l'intérieur de votre robot pour, par exemple, identifier votre concurrent et prédire ses actions. Vous pouvez, bien sûr, essayer de déterminer la stratégie de votre adversaire.
  • N'essayez pas de jouer avec le contrôleur, les autres concurrents ou mon ordinateur. Ne vous connectez pas à des sources d'informations externes.

Le controlle

La version actuelle du contrôleur se trouve ici . Il est écrit en Java 8. Le fichier "Tournoi" est le contrôleur principal, qui contient également la liste des concurrents (si vous souhaitez héberger vos propres compétitions).


Classement

Je n'ai pas vraiment pu mettre à jour le classement très souvent. Je suis plutôt occupé ce week-end. Par "plutôt occupé", je veux dire pas d'accès à un ordinateur de 6h30 à 21h30. Voici les scores après 5 runs. Le bot "Echo" a continué à perdre pour une raison quelconque (peut-être ma faute, je n'ai pas encore enquêté).

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

Crédit

Un grand merci à Rainbolt et Peter Taylor pour leur aide avec le contrôleur.


1
@ MartinBüttner Ruby 2.1.5 a été ajouté.
PhiNotPi

Comment fonctionne le tournoi à la ronde? Player1 vs Player2 1000 fois, Player1 vs Player3 1000 fois etc ... OU est-ce Player1 vs Player2 une fois puis player1 vs player 3 une fois etc ...
Vajura

@Vajura Un tournoi unique est composé d'une bataille entre chaque paire. Une bataille a 1000 tours, le score total le plus élevé à la fin de la bataille déterminant qui obtient les deux points de victoire. Le tableau de bord actuel montre le total des points de victoire après 40 tournois.
PhiNotPi

Désolé pour les retards dans la mise à jour du forum. Je suis extrêmement occupé ce week-end. Attendez-vous et mettez à jour ce soir et demain matin.
PhiNotPi

Wow, je ne m'attendais pas à ce que mon bot fasse si bien! Aussi, que signifient les chiffres par le premier ensemble de résultats ... nombre de victoires?
mbomb007

Réponses:


17

Morra Cowbell

Pour tous ceux qui recherchent une signification au nom de ce bot, le nom Morra me fait penser à Space Italian , alors j'ai pensé que j'avais besoin d'un nom qui jouait dessus. Parmi les autres candidats, Morra vous a trompé et Morra pour moi .

Il s'agit d'une classe complète implémentant l' Playerinterface. Explication ci-dessous.

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

Explication

J'ai commencé par analyser les jeux avec moins de doigts. La plus simple et non triviale permet les appels de 0ou 1et a la table de gains suivante (les valeurs sont les gains pour le joueur de ligne):

       (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)stratégie est dominée par (0,1), nous pouvons donc réduire le tableau à

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

Maintenant, la (1,0)stratégie est dominée par (0,1), afin que nous puissions réduire davantage le tableau à

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

Et maintenant (1,1)est dominé par (0,1), donc nous nous retrouvons avec

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

Par conséquent, toujours jouer (0,1)est un équilibre de Nash. Mais ce qui est curieux, c'est que ce n'est pas le seul. Il s'agit d'un jeu symétrique à somme nulle, donc le gain attendu est de 0, et toute stratégie mixte combinant (0,1)et (1,0)(0,1)est choisie au moins 50% du temps réalise ce gain. Nous avons donc un espace unidimensionnel d'équilibres de Nash.

Il semble que ce soit le cas, même si je ne l'ai pas prouvé, que n-finger Morra a un npolytope dimensionnel d'équilibres de Nash qui sont des stratégies mixtes entre les n+1 (pick, guess)paires pour lesquelles pick + guess = n.

Les nombres magiques dans le code ci-dessus codent les 32 sommets du polytope à 5 dimensions des équilibres de Nash. Je les ai trouvés en créant une instance de programmation linéaire qui représentait le polytope et en utilisant ensuite des fonctions objectives aléatoires. La raison pour encoder les 32 plutôt que d'en choisir un est simple: le gain attendu est 0, donc je dois faire mieux que prévu pour gagner. Je suppose essentiellement que l'autre joueur utilise une stratégie mixte et estime la distribution en fonction de son historique de choix. Ensuite, je sélectionne le sommet du polytope qui maximise mon gain attendu par rapport à cette distribution estimée.

QuinnAndValor démontre la vulnérabilité de l'hypothèse que l'autre joueur utilise une stratégie mixte. En détectant un joueur qui utilise les stratégies des équilibres de Nash, il est capable de basculer dans un mode de marche aléatoire où, jouant une stratégie de non-équilibre, il est susceptible de perdre en moyenne, mais il n'a besoin que de prendre l'avantage une fois puis il peut revenir à jouer des paires pour lesquelles pick + guess = n. Ainsi, les équilibres de Nash pour un seul jeu ne se généralisent pas de manière triviale aux équilibres de Nash pour le jeu répété, ce qui permet des stratégies plus complexes.


4
Est-il possible que votre magie contienne une partie des numéros de Hamming ? Il ne les contient certainement pas tous, mais beaucoup ( ou tous? ) Sont dans la liste de ce site Web.
GiantTree

@GiantTree, ce sont tous des numéros de Hamming. Observation intéressante.
Peter Taylor

Pas étonnant que votre robot devienne jambon. : D
mbomb007

11

Quinn et Valor (mis à jour)

Quinn et Valor sont une équipe de rangers d'élite. Avec l'arbalète et la griffe, ils déchirent chaque adversaire ose les défier.

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

Ils gagnent presque toujours contre toutes les solutions Java sur ma machine.

Modifier:

J'avoue que Quinn et Valor n'ont pas réussi à se battre en historien, mais j'ai toujours bonne foi en eux pour remporter le tournoi.

Mon principe est, pour toute solution avec choice + guess == 5, de jouer aussi avec les choice + guess == 5bénéficiaires en gardant votre avantage.

Mise à jour:

Eh bien ... tout est devenu compliqué.


1
J'aime la référence de League of Legends. Je veux vraiment faire un robot Teemo maintenant. :)
mbomb007

6

Savant

Le chercheur essaie d'apprendre des mouvements de son adversaire, choisissant celui que son adversaire a le moins deviné et devinant celui que son adversaire a le plus utilisé. Mais la théorie n'est pas tout, donc Scholar ne fait pas très bien ...

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

(Mis à jour pour ne pas utiliser de fichiers et ajouté une nouvelle section. Également modifié pour ne plus se coincer dans la première section.)

Consiste en quelques stratégies qui commencent simples puis deviennent plus complexes - si vous en supprimez une, cela vous fait passer à la section suivante.

  • Section 1: Devinez {0, 5}régulièrement
  • Section 2: Vérifiez si vos 4 dernières suppositions forment un motif constant, linéaire ou quadratique et continuez à deviner le motif jusqu'à ce qu'il se casse
  • Section 3: Vérifiez si vous devinez une quantité anormalement basse d'un certain nombre (moins de 1/13) et choisissez ce nombre
  • Section 4: Analysez les bigrammes dans vos choix et regardez ce qui est le plus susceptible de sortir ensuite
  • Section 5: Regardez les 100 dernières rondes et choisissez la (choice, guess)paire qui aurait la meilleure attente, pondérée de sorte que les rondes récentes soient plus importantes
  • Section finale: Devinez au hasard, avec une probabilité plus élevée d'avoir des choix bas et des suppositions élevées. Si vous arrivez ici, alors DeltaMax a abandonné et voudrait dire "bon jeu".

Pour savoir quelle stratégie a finalement été utilisée, décommentez

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

ligne.

Toutes mes excuses pour l'horrible Java, j'ai passé mon après-midi à reconstituer des morceaux et à réapprendre le langage :)

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

Avec l'implémentation actuelle du contrôleur, il n'est pas nécessaire d'enregistrer des éléments dans un fichier si les données ne sont utilisées que pour un seul jeu. c'est à dire private int strat;est assez bon.
johnchen902

@ johnchen902 Merci, je ne savais pas que je pouvais faire ça. Cela rend les choses beaucoup plus faciles.
Sp3000

6

Historien

(Mise à jour: même logique, code plus court et 100 fois plus rapide, mais vous ne pouvez utiliser qu'un seul bot historien lors d'un tournoi.)

Utilise une pondération aléatoire pour choisir une paire de lancer-deviner basée sur l'efficacité de n'utiliser que cette paire contre l'historique précédent de l'adversaire. Les poids sont les carrés des scores réalisables.

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

Beats Quinn and Valor (pas plus) et perd à Morra Cowbell. Dans le tournoi, la plupart des bots Historianarrivent en deuxième position Quinn and Valor.


C'est bien de voir que j'ai gagné sur la machine de quelqu'un. Je suis en train de perdre le tableau des leaders officiels actuel . Je me demandais à cause de la malchance ou d'un bug subtil imprévu.
johnchen902

@ johnchen902 Je dois avoir des coups hallucinés Morra Cowbell. Modifié le message. Vous pouvez cependant supprimer les commentaires s'ils deviennent obsolètes.
randomra

Je pense que je peux gagner 75% de notre duel maintenant après ma mise à jour!
johnchen902

5

Extrapolateur (v1.1)

Extrapolation extrême à partir de l'un des équilibres de Nash d'un jeu plus simple.

Je soutiens le format de réponse concise! (En style python.)

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

Semble égaler avec la vache magique (Morra Cowbell) et bat les autres entrées que j'ai vérifiées.


1
Veuillez déplacer le R aléatoire dans un champ statique, afin de ne pas l'initialiser à chaque fois, cela améliorera les performances globales!
Falco

Pourquoi le changement de distribution?
Peter Taylor

4

Branché

Trendy jette un œil aux mouvements passés de l'adversaire, en les pondérant par la récence. Devine le plus lourd, et en choisit un légèrement décalé. Le voici, dans toute sa splendeur:

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

La seule chose avec laquelle je peux le comparer maintenant est Cowbell. Il perd par une petite marge la plupart du temps, mais ressort souvent assez souvent à mon goût. Nous verrons comment cela se passe avec plus de concurrents.


7
Pourriez-vous s'il vous plaît formater le code sur plusieurs lignes? Ce n'est pas du golf de code ...
mbomb007

7
@ mbomb007 Cela prend moins d'espace de cette façon. L'une des douleurs des KotH en général est tout le défilement pour regarder les entrées. J'ai décrit ce qu'il fait et il est très simple pour les parties intéressées de le formater.
Geobits

4

Devineur aléatoire

C'est vraiment simple. Il lance effectivement un d6 et ajoute un autre rouleau au rouleau précédent pour sa conjecture. Il ne gagnera pas, mais il fournira une belle référence.

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

Confus, Python 3

Une entrée inutilement compliquée. Même moi, je ne sais pas ce que ça fait.

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

Bien que cet algorithme avancé semble moins performant qu'aléatoire dans ce tournoi, et utilise une mémoire et une durée d'exécution importantes, il a des résultats étonnants pour certaines valeurs de 5 ;-)


4

Rainbolt

Prend la différence entre les deux derniers chiffres que notre adversaire a deviné, ajoute cela à la dernière supposition de notre adversaire, trouve le module et évite de choisir ce numéro à tout prix. Par exemple, si vous devinez {5,4,3} (en diminuant d'une unité), nous éviterions à tout prix d'en choisir 2.

Prend la différence entre les deux derniers nombres choisis par notre adversaire, ajoute cela au dernier choix de notre adversaire et devine ce nombre. Par exemple, si vous devinez {1,4,5,2} (augmentant par trois), nous devinerions 5.

Evite les rouleaux inutiles ou très proches.

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

Ne rendez pas votre getMove()méthode statique. Vous ne pouvez pas implémenter une méthode non statique comme celle-ci (du moins pas en Java 8).
GiantTree

@GiantTree Merci d'avoir attrapé ça.
Rainbolt

3

Bot évolué

J'ai fait évoluer ce bot pour qu'il soit le meilleur bot aléatoire.

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é, Python 3

Calculez la supposition en fonction des nombres populaires utilisés dans le passé par l'adversaire. Les chiffres utilisés récemment ont plus de poids. Le choix du nombre est souvent le même que la supposition.

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

Interpolateur

(Passé à Java car Python posait des problèmes)

Utilise une interpolation polynomiale sur les 10 derniers choix de l'adversaire pour déterminer le numéro suivant de l'adversaire, puis fait de même pour ses propres choix et évite de choisir ce numéro. De plus, Interpolator a un léger biais contre le choix de 0 ou 5, et son choix est parfois affecté par sa supposition:

  • S'il devine 0, il ne choisira jamais 0
  • S'il devine 5, il choisira toujours 0 ou 1
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

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

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

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

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

        return ints;
    }

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

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

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

        if (allEqual) {
            return nums[0];

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

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

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

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

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

        return tailArray;
    }

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

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

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

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

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

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

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

        return new int[] {choice, guess};
    }
}

3

CounterBot

Ne contrecarre personne mais compte plutôt de 0 à 5 dans un cercle ( 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

Basilic, Python

Selon la légende, le basilic est le roi des serpents. ( source ) J'ai pensé que c'était un nom approprié pour un bot qui joue "The Noble Game Of Kings" et est écrit en python. = D Ce bot fait peur au cœur des autres bots et provoque la mort d'un seul coup d'œil.

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)

Cela fonctionne sur une stratégie assez simple. Je ne m'attends pas à ce qu'il gagne, mais c'était amusant d'écrire. C'est également mon premier défi KoTH, donc je suis ravi de voir à quel point il fonctionne.

Comment il choisit son prochain coup.

Le Basilic effectue toujours le coup que son adversaire a deviné le moins de fois. En cas d'égalité, il choisira le plus petit nombre. (pour minimiser le nombre de points de l'adversaire.)

Comment il choisit sa prochaine supposition.

Le basilic choisira la réponse la plus probable à sa supposition précédente. Par exemple, si la dernière fois, il a deviné un 3, il reviendra à travers toutes les fois précédentes où il a deviné un 3, puis retourne le coup de l'adversaire le plus courant qui vient après une supposition de 3. En cas d'égalité , il choisira le plus grand nombre (pour maximiser le nombre de points qu'il pourrait faire.)

Sur une note technique, cela fonctionnera-t-il correctement? Est-ce que print () est suffisant, ou devrais-je utiliser quelque chose comme sys.stdout.write () comme les autres Pythonistas l'ont fait?


sys.stdout.write () fonctionne dans l'un ou l'autre Python. print () ne fonctionne qu'en Python 3. Cela devrait cependant être correct.
TheNumberOne

Non, print () fonctionne dans les deux cas, j'en suis sûr. Les parenthèses sont facultatives dans 2.x
DJMcMayhem

Selon cela , ils fonctionnent différemment. Cependant, la façon dont vous l'utilisez n'a pas d'importance.
TheNumberOne

Mais cela fait-il une différence?
DJMcMayhem

Apparemment non.
TheNumberOne

2

Idem

Cela devient l'adversaire, mais derrière par une supposition / choix.

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

Lance toujours 0 pour minimiser les gains de l'adversaire. Si l'adversaire devine jamais mon numéro, il ne gagne que ce qu'il a lancé.

Devine toujours 5 pour maximiser mes gains. Comme je ne peux obtenir aucun point de mon lancer, je veux en obtenir autant de l'adversaire. Je pourrais deviner au hasard, mais où est le plaisir là-dedans?

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

Je suppose que ce bot fera terriblement. Tout bot utilisant des cotes obtiendra peut-être même chaque supposition juste après la première.
mbomb007

@ mbomb007 Mais ce n'est pas le pire! Bien qu'il fonctionne moins bien que votre RandomBot.
Brian J

1

Erratica, Java

Pas génial, mais il a été initialement conçu pour être principalement aléatoire, jusqu'à ce que la valeur du compromis me soit apparue. Gère de façon constante contre 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

Echo, Ruby

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

unless mychoices
 puts "0 5"
 exit
end

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

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

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

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

Joue le dernier jeu joué par l'adversaire, sur la théorie que n'importe qui peut faire un bot qu'il ne peut pas prédire. Devine en fonction de la valeur attendue à l'aide d'un échantillon de cent mouvements.


J'obtiens cette erreur: echo.rb:3:in <main> ': méthode non définie size' for nil:NilClass (NoMethodError). Cela ne semble se produire qu'au premier tour, quand il n'y a pas d'historique de mouvement.
PhiNotPi

Bizarre, cela ne s'est pas produit lorsque j'ai testé. Je vais éditer.
histocrate

Quelle est la pertinence de la if (mychoices.size > 990 && myscore == '0') nextchoice = rand(1..5)pièce?
randomra

S'il est sur le point de se retrouver dans une égalité sans but (comme cela se produirait, par exemple, contre lui-même), il commence à jouer au hasard, car ~ 50% de chances de gagner est mieux que rien.
histocrate

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

    }
}

Ce mec est composé d'alghorithmes de mauvaise estimation qui utilisent principalement des tableaux pondérés.


Sera dans la prochaine mise à jour.
PhiNotPi

1

Euh euh. Je sais ce que tu penses. "Est-ce qu'il va en choisir cinq ou autre chose?" Eh bien, pour vous dire la vérité dans toute cette excitation, je ne suis pas sûr moi-même, mais étant une méthode .44, la méthode la plus puissante au monde et qui surchargerait votre pile tout de suite, vous devez vous poser une question : "Est-ce que je me sens chanceux?"

Eh bien, punk?

public class DirtyHarry implements Player {

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

    @Override
    public int[] getMove(String[] args) {
        return new int[]{5, 5};
    }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.