Bon contre le mal

112

Résultats - 19 juillet 2014

Le roi de la colline actuel est Mercenary par l'utilisateur Fabigler ! Continuez à envoyer des entrées et renversez-le de son trône!

Cliquez ici pour voir le tableau de bord.

Les programmes soumis au plus tard le 19 juillet 2014 ont été inclus. Toutes les autres soumissions seront incluses dans les essais futurs. Les nouveaux résultats devraient être publiés vers le 9 août, ce qui vous laisse suffisamment de temps.


Illustration dessinée par frère Illustré par Chris Rainbolt, mon frère et une nouvelle diplômée du Savannah College of Art and Design

introduction

Les anges et les démons se battent et, comme d'habitude, utilisent la terre comme champ de bataille. Les humains sont coincés au milieu et sont obligés de prendre parti. Une force neutre inconnue récompense ceux qui se battent toujours pour le côté des perdants.

Le jeu

À chaque essai, vous serez jumelé de manière pseudo-aléatoire, puis mélangé avec 20 à 30 autres soumissions. Chaque essai consistera en 1000 tours. À chaque tour, vous recevrez une entrée et vous devrez produire une sortie. Votre sortie sera enregistrée et notée. Ce processus sera répété 1000 fois.

Contribution

Vous recevrez un seul argument qui représente les votes passés de chaque joueur. Les tours sont délimités par une virgule. A 0représente un joueur qui a pris le parti de Evil ce tour. A 1représente un joueur qui a pris le parti du bien. Dans un essai, les joueurs seront toujours dans le même ordre. Votre propre vote sera inclus, mais pas explicitement identifié. Par exemple:

101 100 100

Dans cet exemple, trois tours ont été complétés et trois joueurs sont en compétition. Le joueur 1 a toujours pris le parti du Bien. Le joueur 2 a toujours pris le parti du Mal. Le joueur trois a basculé du bon du tour 1 au mal des tours 2 et 3. L'un de ces joueurs était vous.

Sortie

Soumissions Java

  • Renvoyez la chaîne goodsi vous voulez vous associer à Good.
  • Renvoyez la chaîne evilsi vous souhaitez vous associer au mal.

Soumissions non Java

  • Générez la chaîne goodsur stdout si vous souhaitez vous associer à Good.
  • Exportez la chaîne evilsur stdout si vous souhaitez vous associer à Evil.

Si votre programme génère ou renvoie autre chose, lève une exception, ne compile pas ou prend plus d'une seconde pour générer quoi que ce soit sur cette machine exacte , il sera alors disqualifié.

Notation

Les scores seront publiés dans une feuille de calcul Google Documents pour faciliter la visualisation dès que je pourrai compiler toutes les entrées actuelles. Ne vous inquiétez pas, je continuerai à faire des essais aussi longtemps que vous continuerez à soumettre des programmes!

  • Vous recevez 3 points si vous vous alliez avec la majorité pendant un tour.
  • Vous recevez n - 1 points si vous vous associez à la minorité pendant un tour, où n est le nombre de fois consécutives où vous vous êtes rangé du côté de la minorité.

Votre score sera la médiane de 5 essais. Chaque essai comprend 1000 tours.

Livrables

Soumissions non Java

Vous devez soumettre un titre unique, un programme et une chaîne de ligne de commande Windows qui exécutera votre programme. Rappelez-vous qu'un argument peut être ajouté à cette chaîne. Par exemple:

  • python Angel.py
    • Notez que celui-ci n'a pas d'arguments. C'est le premier tour! Soyez prêt pour cela.
  • python Angel.py 11011,00101,11101,11111,00001,11001,11001

Soumissions Java

Vous devez soumettre un titre unique et une classe Java qui étend la classe humaine abstraite écrite ci-dessous.

public abstract class Human {
    public abstract String takeSides(String history) throws Exception;
}

Essai

Si vous souhaitez tester votre propre soumission, suivez les instructions ci- dessous .

Notes complémentaires

Vous pouvez soumettre autant de soumissions différentes que vous le souhaitez. Les soumissions qui semblent collusoires seront disqualifiées. L'auteur de cette contestation sera le seul juge en la matière.

Une nouvelle instance de votre programme ou classe Java sera créée à chaque appel. Vous pouvez conserver des informations en écrivant dans un fichier. Vous ne pouvez pas modifier la structure ou le comportement de quoi que ce soit à l'exception de votre propre classe.

Les joueurs seront mélangés avant le début du procès. Demon et Angel participeront à tous les essais. Si le nombre de joueurs est pair, Petyr Baelish rejoindra également. Demon se bat pour le mal, Angel pour le bien et Petyr Baelish choisit un côté pseudo-aléatoire.

Rainbolt
la source
2
Commentaires supprimés, car ils étaient obsolètes et à la demande de OP. S'il vous plaît, informez-moi de tout commentaire qui doit être supprimé.
Poignée de porte
7
Woah, OP change son nom d'utilisateur. Ok, quand le résultat sera-t-il affiché?
moitié le
6
@Rainbolt Cela doit être un putain de boulot, relever ce défi! La raison de cette quantité d’attention est la simplicité du protocole et des règles, le rendant accessible tout en permettant des entrées simples et fonctionnelles . TL; DR: Votre défi est trop beau! : D
tomsmeding le
3
@dgel Je posterai les données brutes, supérieure, inférieure, moyennes et peut-être un graphique en courbes afin que nous puissions voir qui a fait mieux alors que la concurrence se prolongeait.
Rainbolt
6
L'un des pods s'est retrouvé avec 10 entrées qui ont voté de la même manière à chaque fois. En conséquence, deux utilisateurs se sont retrouvés avec des scores parfaits ou "un tour en moins" parfaits d’environ 450 000. Les mêmes entrées ont marqué autour de 1900 dans d'autres essais. Le score moyen est proche de 2000. En raison du déséquilibre extrême dans les résultats, j'ai décidé qu'un nombre plus significatif serait une médiane. J'ai édité le défi de telle sorte qu'après 5 essais, le gagnant sera la soumission avec la médiane la plus élevée. Si quelqu'un pense que passer de la moyenne à la médiane est injuste ou constitue un mauvais choix, veuillez commenter.
Rainbolt

Réponses:

11

Le mercenaire

Toujours du côté de celui qui a payé le plus d'argent lors du dernier tour.

En prenant en compte que les bonnes personnes gagnent statistiquement plus.

package Humans;
public class Mercenary extends Human {
    public String takeSides(String history) {
        // first round random!
        if (history.length() == 0) {
            return Math.random() >= 0.5 ? "good" : "evil";
        }

        String[] rounds = history.split(",");
        String lastRound = rounds[rounds.length - 1];

        double goodMoneyPaid = 0;
        double evilMoneyPaid = 0;
        for (char c : lastRound.toCharArray()) {
                switch (c) {
                case '0':
                    goodMoneyPaid = goodMoneyPaid + 0.2; //statistically proven: good people have more reliable incomes
                    break;
                case '1':
                    evilMoneyPaid++; 
                    break;
                default:
                    break;
                }
        }

        if (goodMoneyPaid > evilMoneyPaid)
        {
            return "good";
        } else {
            return "evil";
        }
    }
}
fabigler
la source
2
C'est le deuxième article à dire quelque chose à propos de l'argent. Est-ce que je manque une référence ou quelque chose?
Rainbolt
C'est vrai, mais ce type est un bâtard encore plus méchant. Déserter ses copains à chaque tour, uniquement pour des raisons d'argent.
Fabigler
Votre instruction switch manquait d'une instruction return pour le cas par défaut, ce qui l'empêchait de se compiler. J'ai ajouté un au hasard.
Rainbolt
4
Félicitations, roi de la colline! Je ne comprends pas comment cette entrée gagne. Voulez-vous ajouter une explication, maintenant qu’il est associé à une prime de 300 points de réputation?
Rainbolt
4
Peut-être un bug, ou j'ai mal compris les commentaires et la description, mais le Mercenary ne fait pas ce qu'il était censé faire. À l'exception du premier tour au hasard, il sera toujours du côté du mal à moins que moins de 1/6 de la population ait voté pour le mal lors du tour précédent.
jaybz
39

Hipster, rubis

if ARGV.length == 0
    puts ["good", "evil"].sample
else
    last_round = ARGV[0].split(',').last
    n_players = last_round.length
    puts last_round.count('1') > n_players/2 ? "evil" : "good"
end

Tout simplement avec la minorité du dernier tour, simplement parce que tout le reste est grand public.

Courir comme

ruby hipster.rb
Martin Ender
la source
30

Petyr Baelish

Vous ne savez jamais de quel côté est Petyr Baelish.

package Humans;

/**
 * Always keep your foes confused. If they are never certain who you are or 
 * what you want, they cannot know what you are likely to do next.
 * @author Rusher
 */
public class PetyrBaelish extends Human {

    /**
     * Randomly take the side of good or evil.
     * @param history The past votes of every player
     * @return A String "good" or "evil
     */
    public String takeSides(String history) {
        return Math.random() < 0.5 ? "good" : "evil";
    }
}

Cette entrée ne sera incluse que si le nombre de joueurs est pair. Cela garantit qu'il y aura toujours une majorité.

Rainbolt
la source
28
Du côté de Petyr Baelish, évidemment.
Cthulhu
2
@ Kevin Il bat régulièrement la plupart des bots. Il marque généralement 27ish.
cjfaure
3
@Kevin Cet article a été soumis par l'auteur du défi. Ce n'était pas fait pour bien faire. Il existe pour assurer qu'il y aura toujours une majorité, car avec un nombre pair de joueurs, il pourrait y avoir une égalité.
Rainbolt
4
Pourquoi, mon Dieu, pourquoi celui-ci a-t-il obtenu le plus de votes? C'est juste pas juste .
Tomsmeding
3
@tomsmeding No. C'est une citation de Game of Thrones lol.
Rainbolt
29

C ++, le méta-scientifique

Celui-ci fait essentiellement la même chose que The Scientist, mais ne fonctionne pas sur les rondes dans leur ensemble, mais sur les joueurs individuels. Il essaie de mapper une vague (ou une fonction constante) sur chaque joueur séparément et prédit son déplacement au tour suivant. Sur la base de la prédiction du tour, Meta Scientist choisit le côté qui ressemble le plus à une majorité.

#include <iostream>
#include <utility>
#include <cstdlib>
#include <cstring>
#if 0
#define DBG(st) {st}
#else
#define DBG(st)
#endif

#define WINDOW (200)

using namespace std;

int main(int argc,char **argv){
    if(argc==1){
        cout<<(rand()%2?"good":"evil")<<endl;
        return 0;
    }
    DBG(cerr<<"WINDOW="<<WINDOW<<endl;)
    int nump,numr;
    nump=strchr(argv[1],',')-argv[1];
    numr=(strlen(argv[1])+1)/(nump+1);
    int period,r,p;
    int score,*scores=new int[WINDOW];
    int max; //some score will always get above 0, because if some score<0, the inverted wave will be >0.
    int phase,phasemax;
    int predicted=0; //The predicted number of goods for the next round
    int fromround=numr-WINDOW;
    if(fromround<0)fromround=0;
    pair<int,int> maxat; //period, phase
    DBG(cerr<<"Players:"<<endl;)
    for(p=0;p<nump;p++){
        DBG(cerr<<" p"<<p<<": ";)
        for(r=fromround;r<numr;r++)if(argv[1][r*(nump+1)+p]!=argv[1][p])break;
        if(r==numr){
            DBG(cerr<<"All equal! prediction="<<argv[1][p]<<endl;)
            predicted+=argv[1][(numr-1)*(nump+1)+p]-'0';
            continue;
        }
        max=0;
        maxat={-1,-1};
        for(period=1;period<=WINDOW;period++){
            scores[period-1]=0;
            phasemax=-1;
            for(phase=0;phase<2*period;phase++){
                score=0;
                for(r=fromround;r<numr;r++){
                    if(argv[1][r*(nump+1)+p]-'0'==1-(r+phase)%(2*period)/period)score++;
                    else score--;
                }
                if(score>scores[period-1]){
                    scores[period-1]=score;
                    phasemax=phase;
                }
            }
            if(scores[period-1]>max){
                max=scores[period-1];
                maxat.first=period;
                maxat.second=phasemax;
            }
            DBG(cerr<<scores[period-1]<<" ";)
        }
        DBG(cerr<<"(max="<<max<<" at {"<<maxat.first<<","<<maxat.second<<"})"<<endl;)
        DBG(cerr<<"     prediction: 1-("<<numr<<"+"<<maxat.second<<")%(2*"<<maxat.first<<")/"<<maxat.first<<"="<<(1-(numr+maxat.second)%(2*maxat.first)/maxat.first)<<endl;)
        predicted+=(1-(numr+maxat.second)%(2*maxat.first)/maxat.first);
    }
    DBG(cerr<<"Predicted outcome: "<<predicted<<" good + "<<(nump-predicted)<<" evil"<<endl;)
    if(predicted>nump/2)cout<<"evil"<<endl; //pick minority
    else cout<<"good"<<endl;
    delete[] scores;
    return 0;
}

Si vous souhaitez activer des instructions de débogage, modifiez la ligne de lecture #if 0à #if 1.

Compilez avec g++ -O3 -std=c++0x -o MetaScientist MetaScientist.cpp(vous n'avez pas besoin d'avertissements, donc non -Wall) et exécutez avec MetaScientist.exe(éventuellement avec l'argument bien sûr). Si vous le demandez vraiment, je peux vous fournir un exécutable Windows.

EDIT: Apparemment, la version précédente a manqué de temps environ 600 tours dans le jeu. Cela ne devrait pas faire ça. Sa consommation de temps est contrôlée par la #define WINDOW (...)ligne, plus elle est lente mais plus lointaine.

tomsmeding
la source
2
Je vous suggère humblement d'essayer de choisir le côté des perdants. Si vous pouvez toujours deviner correctement, vous obtiendrez plus de 3 points par tour.
Kevin
1
@ Kevin C'est vrai, mais j'ai pensé qu'il pourrait rapidement deviner le mauvais côté et que vous devez deviner correctement le côté qui a perdu plus de sept fois d'affilée pour obtenir une amélioration par rapport à la majorité. Je pourrais le changer cependant.
tomsmeding
1
@ Kevin En outre, j'aimerais d'abord voir comment cela se passera (scientifique et méta-scientifique) lorsque Rusher nous fournira un tableau de bord ce week-end, comme il l'a indiqué dans les commentaires au PO. Rusher, désolé, mais je suis trop paresseux pour tout compiler moi-même ... :)
tomsmeding
3
Pas de soucis! Ce n'est probablement pas sûr de les utiliser de toute façon. Laissez-moi juste bousiller ma machine avec le code écrit par 50 inconnus sur Internet.
Rainbolt
1
@ Kevin Mais c'est tellement BEAUCOUP ! Je peux, en effet, mais je n'aime pas ça. Je vais voir comment ces tarifs.
tomsmeding
26

ange

Le joueur le plus pur de tous.

Programme

print "good"

Commander

python Angel.py
Rainbolt
la source
22
Python est un bon langage. Il semble naturel que l'Ange l'utilise.
jpmc26
23
Puis-je rappeler aux gens qu'un Python est un serpent. Un serpent.
M. Lister
3
@ MrLister Puis-je vous rappeler que Lucifer était un grand ange avant que Dieu ne le chasse du paradis?
Zibbobz
1
@ Zibbobz Ouais ... dommage, ils se sont brouillés. Ils auraient pu accomplir tant de choses ensemble.
M. Lister
24

Artemis Fowl

package Humans;

public class ArtemisFowl extends Human {
    public final String takeSides(String history) {
        int good = 0, evil = 0;
        for(int i = 0; i < history.length(); i++)   {
            switch(history.charAt(i))   {
                case '0': evil++; break;
                case '1': good++; break;
            }
        }
        if(good % 5 == 0){
           return "good";
        } else if (evil % 5 == 0){
           return "evil";
        } else {
           if(good > evil){
              return "good";
           } else if(evil > good){
              return "evil";
           } else {
              return Math.random() >= 0.5 ? "good" : "evil";
           }
        }
    }
}

Dans le livre 7, The Atlantis Complex , Artemis Fowl a contracté une maladie psychologique (appelée complexe Atlantis) qui l’a obligé à tout faire par multiples de 5 (paroles, actions, etc.). Lorsqu'il n'a pas pu le faire dans un multiple de 5, il a paniqué. Je fais fondamentalement cela: voir si le bien ou le mal (biais intentionnel) est divisible par 5, si ni l’un ne l’est, alors je panique et vois ce qui était le plus grand et couru avec cela ou panique encore plus loin et choisit au hasard.

Kyle Kanos
la source
4
Quand j'ai lu Artemis Fowl au collège, il n'y avait que deux livres. C'est bien de voir qu'il y en a maintenant sept et que Disney en fait un film.
Rainbolt
1
Il y a en fait 8 livres.
Kyle Kanos
7
Plus on est de fous (à moins que vous
lisiez
1
Et vous avez oublié break;dans votre switch.
johnchen902
1
@ johnchen902, @ Manu: Je ne suis pas très expérimenté en Java (j'utilise Fortran90 + et je ne vois que Java ici), d'où mes erreurs. Je les réparerai quand j'arriverai au bureau dans une heure.
Kyle Kanos
19

Parnumerophobe

Les nombres impairs sont terrifiants.

package Humans;

public class Disparnumerophobic extends Human {
    public final String takeSides(String history) {
        int good = 0, evil = 0;
        for(int i = 0; i < history.length(); i++)   {
            switch(history.charAt(i))   {
                case '0': evil++; break;
                case '1': good++;
            }
        }
        if(good%2 == 1 && evil%2 == 0)  return "evil";
        if(evil%2 == 1 && good%2 == 0)  return "good";
        // well shit.... 
        return Math.random() >= 0.5 ? "good" : "evil";
    }
}
pseudonyme117
la source
17
Le commentaire m'a fait rire / renifler.
phyrfox
17

Linus, Ruby

Cherche à confondre les analystes en brisant toujours le schéma .

num_rounds = ARGV[0].to_s.count(',')
LINUS_SEQ = 0xcb13b2d3734ecb4dc8cb134b232c4d3b2dcd3b2d3734ec4d2c8cb134b234dcd3b2d3734ec4d2c8cb134b23734ecb4dcd3b2c4d232c4d2c8cb13b2d3734ecb4dcb232c4d2c8cb13b2d3734ecb4dc8cb134b232c4d3b2dcd3b2d3734ec4d2c8cb134b234dcd3b2d3734ec4d2c8cb134b23734ecb4dcd3b2c4d2c8cb134b2
puts %w[good evil][LINUS_SEQ[num_rounds]]

Enregistrer sous linus.rbet courir avecruby linus.rb

histocrate
la source
16

Le BackPacker

Détermine le joueur qui a le plus choisi la minorité correspondante et choisit son dernier vote.

package Humans;

public class BackPacker extends Human {
    // toggles weather the BackPacker thinks majority is better vs. minority is better
    private static final boolean goWithMajority = false;

    @Override
    public final String takeSides(String history)  {
        if (history == null || history.equals(""))
            return "evil";
        String[] roundVotes = history.split(",");
        int players = roundVotes[0].length();
        int[] winningPlayers = new int[players];
        for (String nextRound : roundVotes) {
            boolean didGoodWin = didGoodWin(nextRound, players);
            for (int player = 0; player < nextRound.length(); player++) {
                boolean playerVotedGood = nextRound.charAt(player) == '1';
                winningPlayers[player] += didPlayerWin(didGoodWin, playerVotedGood);
            }
        }
        int bestScore = -1;
        for (int nextPlayer : winningPlayers)
            if (bestScore < nextPlayer)
                bestScore = nextPlayer;
        int bestPlayer = 0;
        for (int ii = 0; ii < players; ii++) {
            if (winningPlayers[ii] == bestScore) {
                bestPlayer = ii;
                break;
            }
        }
        if (roundVotes[roundVotes.length - 1].charAt(bestPlayer) == '1')
            return "good";
        return "evil";
    }

    private int didPlayerWin(boolean didGoodWin, boolean playerVotedGood) {
        if(goWithMajority) {
            return ((didGoodWin && playerVotedGood) || (!didGoodWin && !playerVotedGood)) ? 1 : 0;
        } else {
            return ((!didGoodWin && playerVotedGood) || (didGoodWin && !playerVotedGood)) ? 1 : 0;
        }
    }

    private boolean didGoodWin(String round, int players) {
        int good = 0;
        for (char next : round.toCharArray())
            good += next == '1' ? 1 : 0;
        return (good * 2) > players;
    }
}

La fouleFollower

Détermine un joueur qui a choisi le plus souvent la majorité correspondante et choisit son dernier vote.

package Humans;

public class CrowdFollower extends Human {
    // toggles weather the FrontPacker thinks majority is better vs. minority is better
    private static final boolean goWithMajority = true;

    @Override
    public final String takeSides(String history)  {
        if (history == null || history.equals(""))
            return "evil";
        String[] roundVotes = history.split(",");
        int players = roundVotes[0].length();
        int[] winningPlayers = new int[players];
        for (String nextRound : roundVotes) {
            boolean didGoodWin = didGoodWin(nextRound, players);
            for (int player = 0; player < nextRound.length(); player++) {
                boolean playerVotedGood = nextRound.charAt(player) == '1';
                winningPlayers[player] += didPlayerWin(didGoodWin, playerVotedGood);
            }
        }
        int bestScore = -1;
        for (int nextPlayer : winningPlayers)
            if (bestScore < nextPlayer)
                bestScore = nextPlayer;
        int bestPlayer = 0;
        for (int ii = 0; ii < players; ii++) {
            if (winningPlayers[ii] == bestScore) {
                bestPlayer = ii;
                break;
            }
        }
        if (roundVotes[roundVotes.length - 1].charAt(bestPlayer) == '1')
            return "good";
        return "evil";
    }

    private int didPlayerWin(boolean didGoodWin, boolean playerVotedGood) {
        if(goWithMajority) {
            return ((didGoodWin && playerVotedGood) || (!didGoodWin && !playerVotedGood)) ? 1 : 0;
        } else playerVotedGood                return ((!didGoodWin && good) || (didGoodWin && !playerVotedGood)) ? 1 : 0;
        }
    }

    private boolean didGoodWin(String round, int players) {
        int good = 0;
        for (char next : round.toCharArray())
            good += next == '1' ? 1 : 0;
        return (good * 2) > players;
    }
}
Angelo Fuchs
la source
Programme très propre!
Rainbolt
Oups, je pense avoir peut-être copié votre programme dans une langue différente.
PyRulez
@Rusher J'ai mis à jour le code et souhaite l'ajouter sous forme de deux entrées, l'une avec goWithMajority = trueet l'autre où c'est false. Est-ce correct ou dois-je ajouter un second BackPacker pour cela?
Angelo Fuchs
@ AngeloNeuschitzer J'ai édité ce post. De cette façon, je n'oublierai pas d'ajouter les deux soumissions. Je vous suggère de changer le nom vraiment peu créatif que je lui ai donné, et peut-être d'ajouter une description aux deux si vous le souhaitez.
Rainbolt
1
@ Rainbolt J'aime mieux votre FrontPacker, en fait. Lol'd.
Tomsmeding
15

Diseuse de bonne aventure

Ce travail est toujours en cours. Je ne l'ai pas encore testé. Je voulais juste savoir si le PO pensait qu'il enfreignait les règles ou non.

L'idée est de simuler le prochain tour en exécutant plusieurs fois tous les autres participants pour obtenir une probabilité du résultat et agir en conséquence.

package Humans;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import sun.net.www.protocol.file.FileURLConnection;

public class FortuneTeller extends Human {

/**
 * Code from http://stackoverflow.com/a/22462785 Private helper method
 *
 * @param directory The directory to start with
 * @param pckgname The package name to search for. Will be needed for
 * getting the Class object.
 * @param classes if a file isn't loaded but still is in the directory
 * @throws ClassNotFoundException
 */
private static void checkDirectory(File directory, String pckgname,
        ArrayList<Class<?>> classes) throws ClassNotFoundException {
    File tmpDirectory;

    if (directory.exists() && directory.isDirectory()) {
        final String[] files = directory.list();

        for (final String file : files) {
            if (file.endsWith(".class")) {
                try {
                    classes.add(Class.forName(pckgname + '.'
                            + file.substring(0, file.length() - 6)));
                } catch (final NoClassDefFoundError e) {
                // do nothing. this class hasn't been found by the
                    // loader, and we don't care.
                }
            } else if ((tmpDirectory = new File(directory, file))
                    .isDirectory()) {
                checkDirectory(tmpDirectory, pckgname + "." + file, classes);
            }
        }
    }
}

/**
 * Private helper method.
 *
 * @param connection the connection to the jar
 * @param pckgname the package name to search for
 * @param classes the current ArrayList of all classes. This method will
 * simply add new classes.
 * @throws ClassNotFoundException if a file isn't loaded but still is in the
 * jar file
 * @throws IOException if it can't correctly read from the jar file.
 */
private static void checkJarFile(JarURLConnection connection,
        String pckgname, ArrayList<Class<?>> classes)
        throws ClassNotFoundException, IOException {
    final JarFile jarFile = connection.getJarFile();
    final Enumeration<JarEntry> entries = jarFile.entries();
    String name;

    for (JarEntry jarEntry = null; entries.hasMoreElements()
            && ((jarEntry = entries.nextElement()) != null);) {
        name = jarEntry.getName();

        if (name.contains(".class")) {
            name = name.substring(0, name.length() - 6).replace('/', '.');

            if (name.contains(pckgname)) {
                classes.add(Class.forName(name));
            }
        }
    }
}

/**
 * Attempts to list all the classes in the specified package as determined
 * by the context class loader
 *
 * @param pckgname the package name to search
 * @return a list of classes that exist within that package
 * @throws ClassNotFoundException if something went wrong
 */
private static ArrayList<Class<?>> getClassesForPackage(String pckgname)
        throws ClassNotFoundException {
    final ArrayList<Class<?>> classes = new ArrayList<Class<?>>();

    try {
        final ClassLoader cld = Thread.currentThread()
                .getContextClassLoader();

        if (cld == null) {
            throw new ClassNotFoundException("Can't get class loader.");
        }

        final Enumeration<URL> resources = cld.getResources(pckgname
                .replace('.', '/'));
        URLConnection connection;

        for (URL url = null; resources.hasMoreElements()
                && ((url = resources.nextElement()) != null);) {
            try {
                connection = url.openConnection();

                if (connection instanceof JarURLConnection) {
                    checkJarFile((JarURLConnection) connection, pckgname,
                            classes);
                } else if (connection instanceof FileURLConnection) {
                    try {
                        checkDirectory(
                                new File(URLDecoder.decode(url.getPath(),
                                                "UTF-8")), pckgname, classes);
                    } catch (final UnsupportedEncodingException ex) {
                        throw new ClassNotFoundException(
                                pckgname
                                + " does not appear to be a valid package (Unsupported encoding)",
                                ex);
                    }
                } else {
                    throw new ClassNotFoundException(pckgname + " ("
                            + url.getPath()
                            + ") does not appear to be a valid package");
                }
            } catch (final IOException ioex) {
                throw new ClassNotFoundException(
                        "IOException was thrown when trying to get all resources for "
                        + pckgname, ioex);
            }
        }
    } catch (final NullPointerException ex) {
        throw new ClassNotFoundException(
                pckgname
                + " does not appear to be a valid package (Null pointer exception)",
                ex);
    } catch (final IOException ioex) {
        throw new ClassNotFoundException(
                "IOException was thrown when trying to get all resources for "
                + pckgname, ioex);
    }

    return classes;
}

private static boolean isRecursiveCall = false;
private static ArrayList<Class<?>> classes;

static {
    if (classes == null) {
        try {
            classes = getClassesForPackage("Humans");
        } catch (ClassNotFoundException ex) {

        }
    }    
}

private String doThePetyrBaelish() {
    return Math.random() >= 0.5 ? "good" : "evil";
}

@Override
public String takeSides(String history) {
    if (isRecursiveCall) {
        return doThePetyrBaelish();
    }
    isRecursiveCall = true;

    int currentRoundGoodCount = 0;
    float probabilityOfGood = 0;
    int roundCount = 0;
    int voteCount = 0;



    do {
        for (int i = 0; i < classes.size(); i++) {
            try {
                if (classes.get(i).getName() == "Humans.FortuneTeller") {
                    continue;
                }

                Human human = (Human) classes.get(i).newInstance();
                String response = human.takeSides(history);
                switch (response) {
                    case "good":
                        currentRoundGoodCount++;
                        voteCount++;
                        break;
                    case "evil":
                        voteCount++;
                        break;
                    default:
                        break;
                }
            } catch (Exception e) {
            }
        }

        probabilityOfGood = (probabilityOfGood * roundCount
                + (float) currentRoundGoodCount / voteCount) / (roundCount + 1);

        roundCount++;
        currentRoundGoodCount = 0;
        voteCount = 0;

    } while (roundCount < 11);

    isRecursiveCall = false;
    if (probabilityOfGood > .7) {
        return "evil";
    }
    if (probabilityOfGood < .3) {
        return "good";
    }

    return doThePetyrBaelish();
}

}
Andris
la source
Si votre bot exécute tous les autres robots avant de répondre, ne faudra-t-il pas plus de 1 pour répondre?
Plannapus
@ Plannapus Je suppose que ce bot présume que tout le monde va pécher par excès de prudence et éviter toute attente de près d'une seconde. Je pense que cela peut valoir la peine de soumettre une entrée qui consiste en une attente de 0,9 seconde, avant de retourner "bon", histoire de gâcher avec lui. En fait, SBoss m'a battu: D
scragar le
Yahhh! Ensuite, je devrais mettre ce bot dans la liste noire de mon code. Ce serait frustrant ... Également avec des entrées différentes dans des environnements différents tels que Python ou Perl, le chargement réitéré de l'interpréteur pourrait suffire à amener ce code au-delà de la limite de temps.
Andris
16
Si quelqu'un d'autre fait la même chose, vous obtenez une boucle infinie.
Brilliand
4
La soumission a expiré. J'ai attaché un profileur, et près d'une demi-seconde est passée à appeler des soumissions. Cela fonctionne au moins bien, alors félicitations pour cela.
Rainbolt
15

C ++, le scientifique

Celui-ci tente, avec l'historique de ce que la majorité a choisi par tour wave( majority()donne le choix de la majorité sur un tour), d'ajuster une onde aux données, de longueur d'onde 2*periodet de phase phase. Ainsi, étant donné 0,1,1,1,0,1,0,1,1,1,0,0,0,1,0qu'il sélectionne period=3, phase=5( maxat=={3,5}): ses scores deviennent 9 3 11 5 5 3 5 7 9 7 7 7 7 7 7. Il boucle sur toutes les périodes possibles et si, pour cette période, le score est supérieur à celui du maximum actuel, il enregistre les événements {period,phase}pour lesquels cela s'est produit.

Il extrapole ensuite la vague trouvée au tour suivant et prend la majorité prédite.

#include <iostream>
#include <utility>
#include <cstdlib>
#include <cstring>
#if 0
#define DBG(st) {st}
#else
#define DBG(st)
#endif

#define WINDOW (700)

using namespace std;

int majority(const char *r){
    int p=0,a=0,b=0;
    while(true){
        if(r[p]=='1')a++;
        else if(r[p]=='0')b++;
        else break;
        p++;
    }
    return a>b;
}

int main(int argc,char **argv){
    if(argc==1){
        cout<<(rand()%2?"good":"evil")<<endl;
        return 0;
    }
    DBG(cerr<<"WINDOW="<<WINDOW<<endl;)
    int nump,numr;
    nump=strchr(argv[1],',')-argv[1];
    numr=(strlen(argv[1])+1)/(nump+1);
    int fromround=numr-30;
    if(fromround<0)fromround=0;
    int period,r;
    int *wave=new int[WINDOW];
    bool allequal=true;
    DBG(cerr<<"wave: ";)
    for(r=fromround;r<numr;r++){
        wave[r-fromround]=majority(argv[1]+r*(nump+1));
        if(wave[r-fromround]!=wave[0])allequal=false;
        DBG(cerr<<wave[r]<<" ";)
    }
    DBG(cerr<<endl;)
    if(allequal){
        DBG(cerr<<"All equal!"<<endl;)
        if(wave[numr-1]==1)cout<<"evil"<<endl; //choose for minority
        else cout<<"good"<<endl;
        return 0;
    }
    int score,*scores=new int[WINDOW];
    int max=0; //some score will always get above 0, because if some score<0, the inverted wave will be >0.
    int phase,phasemax;
    pair<int,int> maxat(-1,-1); //period, phase
    DBG(cerr<<"scores: ";)
    for(period=1;period<=WINDOW;period++){
        scores[period-1]=0;
        phasemax=-1;
        for(phase=0;phase<2*period;phase++){
            score=0;
            for(r=fromround;r<numr;r++){
                if(wave[r]==1-(r+phase)%(2*period)/period)score++;
                else score--;
            }
            if(score>scores[period-1]){
                scores[period-1]=score;
                phasemax=phase;
            }
        }
        if(scores[period-1]>max){
            max=scores[period-1];
            maxat.first=period;
            maxat.second=phasemax;
        }
        DBG(cerr<<scores[period-1]<<" ";)
    }
    DBG(cerr<<"(max="<<max<<" at {"<<maxat.first<<","<<maxat.second<<"})"<<endl;)
    DBG(cerr<<" max: ("<<numr<<"+"<<maxat.second<<")%(2*"<<maxat.first<<")/"<<maxat.first<<"=="<<((numr+maxat.second)%(2*maxat.first)/maxat.first)<<endl;)
    if(1-(numr+maxat.second)%(2*maxat.first)/maxat.first==1)cout<<"evil"<<endl; //choose for minority
    else cout<<"good"<<endl;
    delete[] wave;
    delete[] scores;
    return 0;
}

Compilez avec g++ -O3 -std=c++0x -o Scientist Scientist.cpp(vous n'avez pas besoin d'avertissements, donc non -Wall) et exécutez avec Scientist.exe(éventuellement avec l'argument bien sûr). Si vous le demandez vraiment, je peux vous fournir un exécutable Windows.

Oh, et n'ose pas jouer avec le format d'entrée. Cela ferait des choses étranges autrement.

EDIT: Apparemment, la version précédente a manqué de temps environ 600 tours dans le jeu. Cela ne devrait pas faire ça. Sa consommation de temps est contrôlée par la #define WINDOW (...)ligne, plus elle est lente mais plus lointaine.

tomsmeding
la source
8
Télécharger des exécutables écrits par plus de soixante inconnus sur Internet semble être une mauvaise idée.
Rainbolt
@Rusher je suis totalement d'accord. Si vous voulez des problèmes, c'est la première étape du guide "pour les nuls". Mon offre reste cependant :)
tomsmeding
2
Vous avez celui-ci pour compiler (et concourir) bien.
Rainbolt
14

Coureur de code

Donc, pour rendre les choses intéressantes, j'ai créé un script pour télécharger automatiquement le code de chaque réponse postée, le compiler si nécessaire, puis exécuter toutes les solutions conformément aux règles. De cette façon, les gens peuvent vérifier comment ils vont. Sauvegardez simplement ce script dans run_all.py (nécessite BeautifulSoup), puis:

usage:
To get the latest code: 'python run_all.py get'
To run the submissions: 'python run_all.py run <optional num_runs>'

Quelques choses:

  1. Si vous souhaitez ajouter un support pour plus de langues, ou supprimer le support pour certaines langues, voir def submission_type(lang).
  2. L'extension du script devrait être assez facile, même pour les langues nécessitant une compilation (voir CPPSubmission). Le type de langue est extrait de la balise meta code < !-- language: lang-java -- >. Veillez donc à l'ajouter si vous souhaitez que votre code soit exécuté (supprimez les espaces supplémentaires avant et après le <>). MISE À JOUR : Il existe maintenant une inférence extrêmement basique pour essayer de détecter la langue si elle n'est pas définie.
  3. Si votre code ne parvient pas du tout à s'exécuter ou ne se termine pas dans le délai imparti, il sera ajouté blacklist.textet sera automatiquement supprimé des prochains essais. Si vous corrigez votre code, supprimez simplement votre entrée de la liste noire et relancez-la get,

Langues actuellement supportées:

 submission_types =  {
    'lang-ruby': RubySubmission,
    'lang-python': PythonSubmission,
    'lang-py': PythonSubmission,
    'lang-java': JavaSubmission,
    'lang-Java': JavaSubmission,
    'lang-javascript': NodeSubmission,
    'lang-cpp': CPPSubmission,
    'lang-c': CSubmission,
    'lang-lua': LuaSubmission,
    'lang-r': RSubmission,
    'lang-fortran': FortranSubmission,
    'lang-bash': BashSubmission
}

Sans plus tarder:

import urllib2
import hashlib
import os
import re
import subprocess
import shutil
import time
import multiprocessing
import tempfile
import sys
from bs4 import BeautifulSoup

__run_java__ = """
public class Run {
    public static void main(String[] args) {
        String input = "";
        Human h = new __REPLACE_ME__();
        if(args.length == 1)
            input = args[0];
        try {
            System.out.println(h.takeSides(input));
        }
        catch(Exception e) {
        }
    }
}
"""

__human_java__ = """
public abstract class Human {
    public abstract String takeSides(String history) throws Exception;
}
"""

class Submission():
    def __init__(self, name, code):
        self.name = name
        self.code = code

    def submissions_dir(self):
        return 'submission'

    def base_name(self):
        return 'run'

    def submission_path(self):
        return os.path.join(self.submissions_dir(), self.name)

    def extension(self):
        return ""

    def save_submission(self):
        self.save_code()

    def full_command(self, input):
        return []

    def full_path(self):
        file_name = "%s.%s" % (self.base_name(), self.extension())
        full_path = os.path.join(self.submission_path(), file_name)
        return full_path

    def save_code(self):    
        if not os.path.exists(self.submission_path()):
            os.makedirs(self.submission_path())

        with open(self.full_path(), 'w') as f:
            f.write(self.code)

    def write_err(self, err):
        with open(self.error_log(), 'w') as f:
            f.write(err)

    def error_log(self):
        return os.path.join(self.submission_path(), 'error.txt')

    def run_submission(self, input):
        command = self.full_command()
        if input is not None:
            command.append(input)
        try:
            output,err,exit_code = run(command,timeout=1)
            if len(err) > 0:
                self.write_err(err)
            return output
        except Exception as e:
            self.write_err(str(e))
            return ""

class CPPSubmission(Submission):
    def bin_path(self):
        return os.path.join(self.submission_path(), self.base_name())

    def save_submission(self):
        self.save_code()
        compile_cmd = ['g++', '-O3', '-std=c++0x', '-o', self.bin_path(), self.full_path()]
        errout = open(self.error_log(), 'w')
        subprocess.call(compile_cmd, stdout=errout, stderr=subprocess.STDOUT)

    def extension(self):
        return 'cpp'

    def full_command(self):
        return [self.bin_path()]

class CSubmission(Submission):
    def bin_path(self):
        return os.path.join(self.submission_path(), self.base_name())

    def save_submission(self):
        self.save_code()
        compile_cmd = ['gcc', '-o', self.bin_path(), self.full_path()]
        errout = open(self.error_log(), 'w')
        subprocess.call(compile_cmd, stdout=errout, stderr=subprocess.STDOUT)

    def extension(self):
        return 'c'

    def full_command(self):
        return [self.bin_path()]

class FortranSubmission(Submission):
    def bin_path(self):
        return os.path.join(self.submission_path(), self.base_name())

    def save_submission(self):
        self.save_code()
        compile_cmd = ['gfortran', '-fno-range-check', '-o', self.bin_path(), self.full_path()]
        errout = open(self.error_log(), 'w')
        subprocess.call(compile_cmd, stdout=errout, stderr=subprocess.STDOUT)

    def extension(self):
        return 'f90'

    def full_command(self):
        return [self.bin_path()]

class JavaSubmission(Submission):   
    def base_name(self):
        class_name = re.search(r'class (\w+) extends', self.code)
        file_name = class_name.group(1)
        return file_name

    def human_base_name(self):
        return 'Human'

    def run_base_name(self):
        return 'Run'

    def full_name(self, base_name):
        return '%s.%s' % (base_name, self.extension())

    def human_path(self):
        return os.path.join(self.submission_path(), self.full_name(self.human_base_name()))

    def run_path(self):
        return os.path.join(self.submission_path(), self.full_name(self.run_base_name()))

    def replace_in_file(self, file_name, str_orig, str_new):
        old_data = open(file_name).read()
        new_data = old_data.replace(str_orig, str_new)

        with open(file_name, 'w') as f:
            f.write(new_data)

    def write_code_to_file(self, code_str, file_name):
        with open(file_name, 'w') as f:
            f.write(code_str)

    def save_submission(self):
        self.save_code()
        self.write_code_to_file(__human_java__, self.human_path())
        self.write_code_to_file(__run_java__, self.run_path())

        self.replace_in_file(self.run_path(), '__REPLACE_ME__', self.base_name())
        self.replace_in_file(self.full_path(), 'package Humans;', '')

        compile_cmd = ['javac', '-cp', self.submission_path(), self.run_path()]
        errout = open(self.error_log(), 'w')
        subprocess.call(compile_cmd, stdout=errout, stderr=subprocess.STDOUT)

    def extension(self):
        return 'java'

    def full_command(self):
        return ['java', '-cp', self.submission_path(), self.run_base_name()]

class PythonSubmission(Submission):
    def full_command(self):
        return ['python', self.full_path()]

    def extension(self):
        return 'py'

class RubySubmission(Submission):
    def full_command(self):
        return ['ruby', self.full_path()]

    def extension(self):
        return 'rb'

class NodeSubmission(Submission):
    def full_command(self):
        return ['node', self.full_path()]

    def extension(self):
        return 'js'

class LuaSubmission(Submission):
    def full_command(self):
        return ['lua', self.full_path()]

    def extension(self):
        return 'lua'

class RSubmission(Submission):
    def full_command(self):
        return ['Rscript', self.full_path()]

    def extension(self):
        return 'R'

class BashSubmission(Submission):
    def full_command(self):
        return [self.full_path()]

    def extension(self):
        return '.sh'

class Scraper():
    def download_page(self, url, use_cache = True, force_cache_update = False):
        file_name = hashlib.sha1(url).hexdigest()

        if not os.path.exists('cache'):
            os.makedirs('cache')

        full_path = os.path.join('cache', file_name)
        file_exists = os.path.isfile(full_path)

        if use_cache and file_exists and not force_cache_update:
            html = open(full_path, 'r').read()
            return html

        opener = urllib2.build_opener()
        opener.addheaders = [('User-agent', 'Mozilla/5.0')]
        response = opener.open(url)
        html = response.read()

        if use_cache:
            f = open(full_path, 'w')
            f.write(html)
            f.close()

        return html

    def parse_post(self, post):
        name = post.find(text=lambda t: len(t.strip()) > 0)
        pre = post.find('pre')
        lang = pre.attrs['class'][0] if pre.has_attr('class') else None
        code = pre.find('code').text
        user = post.find(class_='user-details').find(text=True)
        return {'name':name,'lang':lang,'code':code,'user':user}

    def parse_posts(self, html):
        soup = BeautifulSoup(html)
        # Skip the first post
        posts = soup.find_all(class_ = 'answercell')
        return [self.parse_post(post) for post in posts]

    def get_submissions(self,  page = 1, force_cache_update = False):
        url = "http://codegolf.stackexchange.com/questions/33137/good-versus-evil?page=%i&tab=votes#tab-top" % page
        html = self.download_page(url, use_cache = True, force_cache_update = force_cache_update)
        submissions = self.parse_posts(html)
        return submissions

class Timeout(Exception):
    pass

def run(command, timeout=10):
    proc = subprocess.Popen(command, bufsize=0, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    poll_seconds = .250
    deadline = time.time()+timeout
    while time.time() < deadline and proc.poll() == None:
        time.sleep(poll_seconds)

    if proc.poll() == None:
        if float(sys.version[:3]) >= 2.6:
            proc.terminate()
        raise Timeout()

    stdout, stderr = proc.communicate()
    return stdout, stderr, proc.returncode


def guess_lang(code):
    if re.search(r'class .* extends Human', code):
        return 'lang-java'
    if re.search(r'import sys', code):
        return 'lang-python'
    if re.search(r'puts', code) and (re.search(r'ARGV', code) or re.search(r'\%w', code)):
        return 'lang-ruby'
    if re.search(r'console\.log', code):
        return 'lang-javascript'
    if re.search(r'program', code) and re.search(r'subroutine', code):
        return 'lang-fortran'
    if re.search(r'@echo off', code):
        return 'lang-bash'
    return None


def submission_type(lang, code):
    submission_types =  {
        'lang-ruby': RubySubmission,
        'lang-python': PythonSubmission,
        'lang-py': PythonSubmission,
        'lang-java': JavaSubmission,
        'lang-Java': JavaSubmission,
        'lang-javascript': NodeSubmission,
        'lang-cpp': CPPSubmission,
        'lang-c': CSubmission,
        'lang-lua': LuaSubmission,
        'lang-r': RSubmission,
        'lang-fortran': FortranSubmission,
        'lang-bash': BashSubmission
    }

    klass = submission_types.get(lang)

    if klass is None:
        lang = guess_lang(code)
        klass = submission_types.get(lang)

    return klass

def instantiate(submission):
    lang = submission['lang']
    code = submission['code']
    name = submission['name']

    klass = submission_type(lang, code)
    if klass is not None:
        instance = klass(name, code)
        return instance
    print "Entry %s invalid - lang not supported: %s" % (name, lang)
    return None

def get_all_instances(force_update):
    scraper = Scraper()

    print 'Scraping Submissions..'

    pages = [1,2,3]
    submissions_by_page = [scraper.get_submissions(page=i, force_cache_update=force_update) for i in pages]
    submissions = [item for sublist in submissions_by_page for item in sublist]

    # Get instances
    raw_instances = [instantiate(s) for s in submissions]
    instances = [i for i in raw_instances if i]

    print "Using %i/%i Submissions" % (len(instances), len(submissions))

    return instances

def save_submissions(instances):
    print 'Saving Submissions..'

    for instance in instances:
        instance.save_submission()

def init_game(save=True, force_update=False):
    instances = get_all_instances(force_update)
    if save:
        save_submissions(instances)
    return instances

def one_run(instances, input):
    valid = {
        'good': 1,
        'evil': 0
    }

    disqualified = []
    results = []

    for instance in instances:
        out = instance.run_submission(input)
        res = out.strip().lower()
        if res not in valid:
            disqualified.append(instance)
        else:
            results.append(valid[res])

    return (results, disqualified)

def get_winner(scores, instances):
    max_value = max(scores)
    max_index = scores.index(max_value)
    instance = instances[max_index]
    return (instance.name, max_value)

def update_scores(results, scores, minority_counts, minority_num):
    for i in range(len(results)):
        if results[i] == minority_num:
            minority_counts[i] += 1
            scores[i] += (minority_counts[i] - 1)
        else:
            minority_counts[i] = 0
            scores[i] += 3

def try_run_game(instances, num_runs = 1000, blacklist = None):
    current_input = None
    minority_str = None
    num_instances = len(instances)
    scores = [0] * num_instances
    minority_counts = [0] * num_instances

    print "Running with %i instances..." % num_instances

    for i in range(num_runs):
        print "Round: %i - Last minority was %s" % (i, minority_str)
        results, disqualified = one_run(instances, current_input)

        if len(disqualified) > 0:
            for instance in disqualified:
                print "Removing %s!" % instance.name
                instances.remove(instance)

                if blacklist is not None:
                    with open(blacklist, 'a') as f:
                        f.write("%s\n" % instance.name)

            return False

        latest_result = "".join(map(str,results))
        current_input = "%s,%s" % (current_input, latest_result)

        minority_num = 1 if results.count(1) < results.count(0) else 0
        minority_str = 'good' if minority_num == 1 else 'evil'

        update_scores(results, scores, minority_counts, minority_num)
        name, score = get_winner(scores, instances)
        print "%s is currently winning with a score of %i" % (name, score)

    print "The winner is %s with a score of %i!!!" % (name, score)
    return True

def find_instance_by_name(instances, name):
    for instance in instances:
        if instance.name == name:
            return instance
    return None

def maybe_add_or_remove_baelish(instances, baelish):
    num_instances = len(instances)

    if num_instances % 2 == 0:
        print 'There are %i instances.' % num_instances
        try:
            instances.remove(baelish)
            print 'Baelish Removed!'
        except:
            instances.append(baelish)
            print 'Baelish Added!'

def remove_blacklisted(blacklist, instances):
    blacklisted = []

    try:
        blacklisted = open(blacklist).readlines()
    except:
        return

    print 'Removing blacklisted entries...'

    for name in blacklisted:
        name = name.strip()
        instance = find_instance_by_name(instances, name)
        if instance is not None:
            print 'Removing %s' % name
            instances.remove(instance)

def run_game(instances, num_runs):
    blacklist = 'blacklist.txt'
    remove_blacklisted(blacklist, instances)

    baelish = find_instance_by_name(instances, 'Petyr Baelish') 
    maybe_add_or_remove_baelish(instances, baelish)

    while not try_run_game(instances, num_runs = num_runs, blacklist = blacklist):
        print "Restarting!"
        maybe_add_or_remove_baelish(instances, baelish)

    print "Done!"

if __name__ == '__main__':
    param = sys.argv[1] if len(sys.argv) >= 2 else None

    if param == 'get':
        instances = init_game(save=True, force_update=True)
    elif param == 'run':
        instances = init_game(save=False, force_update=False)
        num_runs = 50
        if len(sys.argv) == 3:
            num_runs = int(sys.argv[2])
        run_game(instances, num_runs)
    else:
        self_name = os.path.basename(__file__)
        print "usage:"
        print "To get the latest code: 'python %s get'" % self_name
        print "To run the submissions: 'python %s run <optional num_runs>'" % self_name
WhatAWorld
la source
Pourquoi pas de langue Fortran ??
Kyle Kanos
@KyleKanos - J'ai ajouté un support pour cela, mettra à jour le code sous peu.
WhatAWorld
Yay! J'ai (en quelque sorte) travaillé dur sur ma soumission en Fortran et Rusher ne peut pas le faire fonctionner, alors j'aimerais bien que quelqu'un le reçoive :)
Kyle Kanos
1
@Rusher: Je suis d'accord avec PeterTaylor sur ce point: la syntaxe en surbrillance, en tant que seule modification suggérée, devrait être rejetée. Les modifications doivent être utilisées pour des corrections substantielles et non pour des tâches mineures.
Kyle Kanos
1
Vous méritez bien le représentant pour cela, mais comme ce n’est pas exactement une réponse à la question (et qu’il pourrait probablement bénéficier de l’ajout de choses par la communauté pour d’autres langues), je pense que cela devrait techniquement être un wiki de communauté.
Martin Ender
13

Le bel esprit, Ruby

Prend sa décision en se basant sur des motifs d'importance discutable dans la représentation en bits du dernier tour

require 'prime'

if ARGV.length == 0
    puts ["good", "evil"].sample
else
    last_round = ARGV[0].split(',').last
    puts Prime.prime?(last_round.to_i(2)) ? "good" : "evil"
end

Courir comme

ruby beautiful-mind.rb
Martin Ender
la source
13

Piustitious, Lua

Un programme superstitieux qui croit en Signs and Wonders.

history = arg[1]

if history == nil then
    print("good")
else
    local EvilSigns, GoodSigns = 0,0
    local SoulSpace = ""

    for i in string.gmatch(history, "%d+") do
         SoulSpace = SoulSpace .. i 
    end

    if string.match(SoulSpace, "1010011010")  then -- THE NUBMER OF THE BEAST!
        local r = math.random(1000)
        if r <= 666 then print("evil") else print("good") end
    else
        for i in string.gmatch(SoulSpace, "10100") do -- "I'M COMING" - DEVIL
            EvilSigns = EvilSigns + 1
        end
        for i in string.gmatch(SoulSpace, "11010") do -- "ALL IS WELL" - GOD
            GoodSigns = GoodSigns + 1
        end

        if EvilSigns > GoodSigns then 
            print("evil")
        elseif GoodSigns > EvilSigns then
            print("good")
        elseif GoodSigns == EvilSigns then
            local r = math.random(1000)
            if r <= 666 then print("good") else print("evil") end
        end
    end
end

lancez-le avec:

lua Piustitious.lua

suivi de l'entrée.

AndoDaan
la source
11

Les winchesters

Sam et Dean sont bons (la plupart du temps).

package Humans;

public class TheWinchesters extends Human {

    @Override
    public String takeSides(String history) throws Exception {
        return Math.random() < 0.1 ? "evil" : "good";
    }

}
CommonGuy
la source
Êtes-vous sûr 9:1est le bon ratio? Peut-être devrions-nous faire une exploration de données et obtenir un ratio plus précis?
récursion.ninja
1
@awashburn J'ai commencé à regarder Supernatural il y a 2 mois (maintenant bloqué dans la saison 9) et 9:1ça me semble correct;)
CommonGuy
10

Statisticien

public class Statistician extends Human{
    public final String takeSides(String history) { 
        int side = 0;
        String[] hist = history.split(",");
        for(int i=0;i<hist.length;i++){
            for(char c:hist[i].toCharArray()){
                side += c == '1' ? (i + 1) : -(i + 1);
            }
        }
        if(side == 0) side += Math.round(Math.random());
        return side > 0 ? "good" : "evil";
    }
}
Immérité
la source
5
Cette deuxième ligne est si géniale
cjfaure
5
@Undeserved Au lieu de Math.ceil(Math.random()-Math.random())vous pouvez aussi faire juste Math.round(Math.random()).
tomsmeding
10

R, un bot un peu bayésien

Utilisez la table de fréquences pour chaque utilisateur comme probabilité antérieure de la sortie des autres utilisateurs.

args <- commandArgs(TRUE)
if(length(args)!=0){
    history <- do.call(rbind,strsplit(args,","))
    history <- do.call(rbind,strsplit(history,""))
    tabulated <- apply(history,2,function(x)table(factor(x,0:1)))
    result <- names(which.max(table(apply(tabulated, 2, function(x)sample(0:1,1, prob=x)))))
    if(result=="1"){cat("good")}else{cat("evil")}
}else{
    cat("good")
    }

Invoqué en utilisant Rscript BayesianBot.Rsuivi de l'entrée.

Edit : Juste pour clarifier ce que cela fait, voici une étape par étape avec l'exemple de saisie:

> args
[1] "11011,00101,11101,11111,00001,11001,11001"
> history #Each player is a column, each round a row
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    1    0    1    1
[2,]    0    0    1    0    1
[3,]    1    1    1    0    1
[4,]    1    1    1    1    1
[5,]    0    0    0    0    1
[6,]    1    1    0    0    1
[7,]    1    1    0    0    1

> tabulated #Tally of each player previous decisions.
  [,1] [,2] [,3] [,4] [,5]
0    2    2    4    5    0
1    5    5    3    2    7

Ensuite, la ligne commençant par result<-, pour chaque joueur, choisit aléatoirement 0 ou 1 en utilisant cette dernière table comme poids (c.-à-d. Pour le joueur 1, la probabilité de choisir 0 est de 2 / 7ème, de 1 5/7, etc.). Il choisit un résultat pour chaque joueur / colonne et renvoie finalement le nombre qui a fini par être le plus commun.

planificateur
la source
10

Suisse

Soutient toujours la neutralité. Condamné à ne jamais gagner.

package Humans;

/**
 * Never choosing a side, sustaining neutrality
 * @author Fabian
 */
public class Swiss extends Human {   
    public String takeSides(String history) {
        return "neutral"; // wtf, how boring is that?
    }
}
fabigler
la source
Je n'ai pas écrit ça!
Rainbolt
C'est l'ironie. La neutralité ne gagne jamais
fabigler
2
@Rusher ah je l'ai maintenant: D
fabigler
1
Il ne compile même pas - il manque un point-virgule.
Paŭlo Ebermann
9

HAL 9000

#!/usr/bin/env perl
print eval("evil")

Edit: c'est peut-être plus approprié pour HAL 9000, mais faites attention! C'est très mauvais. Je recommande cdde vider le répertoire avant de l'exécuter.

#!/usr/bin/env perl
print eval {
    ($_) = grep { -f and !/$0$/ } glob('./*');
    unlink;
    evil
}

Cela supprime un fichier cwdpour chaque invocation!

Invocation pas si évidente:

En M $

D:\>copy con hal_9000.pl
#!/usr/bin/env perl
print eval("evil")
^Z
        1 file(s) copied.

D:>hal_9000.pl
evil

En * nix

[core1024@testing_pc ~]$ tee hal_9000.pl
#!/usr/bin/env perl
print eval("evil")
# Press C-D here
[core1024@testing_pc ~]$ chmod +x $_
[core1024@testing_pc ~]$ ./$_
evil[core1024@testing_pc ~]$
core1024
la source
Vous devez fournir une commande pouvant être utilisée pour exécuter votre programme. Voir la section "Livrables" du challenge pour plus d'informations.
Rainbolt
@Rusher Done;)
core1024
9

Volonté de la majorité

import sys
import random

if len(sys.argv)==1:
    print(random.choice(['good','evil']))
else:
    rounds=sys.argv[1].split(',')
    last_round=rounds[-1]
    zeroes=last_round.count('0')
    ones=last_round.count('1')
    if ones>zeroes:
        print('good')
    elif zeroes>ones:
        print('evil')
    elif ones==zeroes:
        print(random.choice(['good','evil']))

Enregistrez-le sous WotM.py, lancez comme python3 WotM.pysuit l'entrée.

Un programme simple, juste pour voir comment ça va se passer. Va avec ce que la majorité a dit la dernière fois, ou bien au hasard.

isaacg
la source
Vous devez fournir une commande pouvant être utilisée pour exécuter votre programme. Voir la section "Livrables" du challenge pour plus d'informations.
Rainbolt
Bon sang, ça fait du mien un duplicata. : D changé le mien en minorité.
Martin Ender
@Rusher A ajouté la commande. C'est ce que tu cherchais?
isaacg
@isaacg Parfait!
Rainbolt
1
J'ai calculé le classement moyen des scores dans le tableau de bord, et cette entrée gagne par cette mesure.
Brilliand
9

Alan Shearer

Répète ce que la personne à côté de laquelle il est assis vient de dire. Si la personne se trompe, elle passe à la personne suivante et répète ce qu'elle dit.

package Humans;

/**
 * Alan Shearer copies someone whilst they're right; if they get predict
 * wrongly then he moves to the next person and copies whatever they say.
 *
 * @author Algy
 * @url http://codegolf.stackexchange.com/questions/33137/good-versus-evil
 */
public class AlanShearer extends Human {

    private char calculateWinner(String round) {
        int good = 0, evil = 0;

        for (int i = 0, L = round.length(); i < L; i++) {
            if (round.charAt(i) == '1') {
                good++;
            } else {
                evil++;
            }
        }

        return (good >= evil) ? '1' : '0';
    }

    /**
     * Take the side of good or evil.
     * @param history The past votes of every player
     * @return A String "good" or "evil
     */
    public String takeSides(String history) {
        String[] parts = history.split(",");
        String lastRound = parts[parts.length() - 1];

        if (parts.length() == 0 || lastRound.length() == 0) {
            return "good";
        } else {
            if (parts.length() == 1) {
                return lastRound.charAt(0) == '1' ? "good" : "evil";
            } else {
                int personToCopy = 0;

                for (int i = 0, L = parts.length(); i < L; i++) {
                    if (parts[i].charAt(personToCopy) != calculateWinner(parts[i])) {
                        personToCopy++;

                        if (personToCopy >= L) {
                            personToCopy = 0;
                        }
                    }
                }
            }

            return lastRound.charAt(personToCopy) == '1' ? "good" : "evil";
        }
    }
}
Algy Taylor
la source
Vous référencez une variable appelée lastRoundavant même de la déclarer. En outre, vous avez ajouté des parenthèses à tous vos éléments, String.lengthmais ce n'est pas une fonction. Pouvez-vous obtenir votre soumission à un point où elle sera compilée?
Rainbolt
@Rusher - terminé :)
Algy Taylor
@Algy: lastRound.lengthest toujours utilisée (dans le premier if) avant lastRoundest déclarée (dans le cas contraire). Essayez de compiler (et éventuellement d’exécuter) votre code avant de le soumettre ici.
Paŭlo Ebermann
@ PaŭloEbermann - excusez-moi, je ne suis pas dans un environnement où je peux l'exécuter - amendement introduit, cependant
Algy Taylor
Vous faites maintenant référence à une variable appelée "personToCopy" lorsqu'elle est hors de portée. Je viens de le déplacer à l'intérieur du bloc else pour qu'il soit compilé, mais je ne sais pas si c'est ce que vous vouliez.
Rainbolt
8

Plus tard, le mal, JavaScript ( node.js )

Mesure la durée entre les exécutions. Si le décalage horaire est plus grand que la dernière fois, il doit être malfaisant. Sinon, bien.

var fs = require('fs'),
currentTime = (new Date).getTime();

try {
    var data = fs.readFileSync('./laterisevil.txt', 'utf8');
} catch (e) { data = '0 0'; } // no file? no problem, let's start out evil at epoch

var parsed = data.match(/(\d+) (\d+)/),
lastTime = +parsed[1],
lastDifference = +parsed[2],
currentDifference = currentTime - lastTime;

fs.writeFileSync('./laterisevil.txt', currentTime + ' ' + currentDifference, 'utf8');
console.log(currentDifference > lastDifference? 'evil' : 'good');

Courir avec: node laterisevil.js

Nderscore
la source
8

Pattern Finder, Python

Cherche un motif récurrent, et s'il ne peut pas en trouver un, va simplement avec la majorité.

import sys

if len(sys.argv) == 1: 
    print('good')
    quit()

wins = ''.join(
    map(lambda s: str(int(s.count('1') > s.count('0'))),
        sys.argv[1].split(',')
    )
)

# look for a repeating pattern
accuracy = []

for n in range(1, len(wins)//2+1):
    predicted = wins[:n]*(len(wins)//n)
    actual    = wins[:len(predicted)]
    n_right = 0
    for p, a in zip(predicted, actual):
        n_right += (p == a)
    accuracy.append(n_right/len(predicted))

# if there's a good repeating pattern, use it
if accuracy:
    best = max(accuracy)
    if best > 0.8:
        n = accuracy.index(best)+1
        prediction = wins[:n][(len(wins))%n]
        # good chance of success by going with minority
        if prediction == '1':
            print('evil')
        else:
            print('good')
        quit()

# if there's no good pattern, just go with the majority
if wins.count('1') > wins.count('0'):
    print('good')
else:
    print('evil')

courir avec

python3 pattern_finder.py
Veste CesiumLife
la source
1
J'aime tellement ce code que quand je le lance, il gagne toujours 3000 points, d'une manière ou d'une autre.
Realdeo
8

Le turncoat

Turncoat pense que, à cause des autres combattants jusqu'à présent, la majorité alternera plus souvent après chaque tour entre le bien et le mal qu'elle ne restera pas du même côté. Ainsi, il commence le premier tour en se rangeant arbitrairement avec bon, puis alterne tous les tours pour tenter de rester le plus souvent dans l'équipe gagnante ou perdante.

package Humans;

public class Turncoat extends Human {
    public final String takeSides(String history) {
        String[] hist = history.split(",");

        return (hist.length % 2) == 0 ? "good" : "evil";
    }
}

Après avoir écrit ceci, je me suis rendu compte qu'en raison des entrées basées sur une analyse statistique, l'élan obligerait la majorité à changer de côté moins à mesure que plus de tours avaient été effectués. Par conséquent, le lazy turncoat.

Le Turncoat Lazy

Le Lazy Turncoat commence comme le Turncoat, mais à mesure que les rounds passent, il devient plus paresseux et plus paresseux pour passer de l’autre côté.

package Humans;

public class LazyTurncoat extends Human {
    public final String takeSides(String history) {
        int round = history.length() == 0 ? 0 : history.split(",").length;
        int momentum = 2 + ((round / 100) * 6);
        int choice = round % momentum;
        int between = momentum / 2;

        return choice < between ? "good" : "evil";
    }
}
Jaybz
la source
2
Le Lazy Turncoat est génial!
Angelo Fuchs
J'inclus les deux si ça ne vous dérange pas.
Rainbolt
Aller de l'avant. Je suis curieux de voir comment les deux vont faire, en particulier par rapport à ceux qui compilent des statistiques de vote.
jaybz
@Rainbolt Je viens de remarquer un bug stupide avec le Turncoat. Pas besoin de le corriger cependant. Cela fonctionne toujours, mais pas tout à fait comme prévu, et même s'il n'est pas trop tard pour le réparer, le faire se comportera exactement comme l'une des entrées les plus récentes. N'hésitez pas à inclure / exclure si vous le souhaitez.
jaybz
8

Biographe, Ruby

rounds = ARGV[0].split(',') rescue []

if rounds.length < 10
  choice = 1
else
  outcome_history = ['x',*rounds.map{|r|['0','1'].max_by{|s|r.count s}.tr('01','ab')}]
  player_histories = rounds.map{|r|r.chars.to_a}.transpose.map{ |hist| outcome_history.zip(hist).join }
  predictions = player_histories.map do |history|
    (10).downto(0) do |i|
      i*=2
      lookbehind = history[-i,i]
      @identical_previous_behavior = history.scan(/(?<=#{lookbehind})[10]/)
      break if @identical_previous_behavior.any?
    end
    if @identical_previous_behavior.any?
      (@identical_previous_behavior.count('1')+1).fdiv(@identical_previous_behavior.size+2)
    else
      0.5
    end
  end
  simulations = (1..1000).map do
    votes = predictions.map{ |chance| rand < chance ? 1 : 0 }
    [0,1].max_by { |i| votes.count(i) }
  end
  choice = case simulations.count(1)/10
    when 0..15
      1
    when 16..50
      0
    when 51..84
      1
    when 85..100
      0
  end
end

puts %w[evil good][choice]

Ma tentative d’une entrée presque intelligente (une entrée réellement intelligente nécessiterait des tests sur le terrain). Écrit en Ruby, il y a donc des chances pour que ce soit trop lent, mais sur ma machine, cela prend 11 secondes pour calculer le dernier tour alors qu'il y a 40 joueurs aléatoires. J'espère donc que cela fonctionnera assez bien.

enregistrer sous biographer.rb, exécuter commeruby biographer.rb

L’idée est que, pour chaque joueur, il estime leurs chances de choisir "bon" en examinant à la fois leurs propres choix pour les dix derniers tours et les résultats globaux, et en trouvant des exemples dans le passé où des circonstances identiques (leurs votes + leur résultats) Il choisit la plus longue longueur de recherche, jusqu'à 10 tours, de sorte qu'il y ait un précédent, et l'utilise pour créer une fréquence (ajustée selon la loi de Laplace sur la succession, afin que nous ne soyons jamais sûrs à 100% de quiconque).

Il effectue ensuite des simulations et voit à quelle fréquence Good gagne. Si les simulations se déroulent généralement de la même manière, les prévisions seront probablement bonnes, de sorte que la minorité prédite sera choisie. S'il n'est pas confiant, il choisit la majorité prédite.

histocrate
la source
8

Judas

Judas est une très bonne personne. Dommage qu'il trahisse les bons pour quelques sous.

package Humans;

public class Judas extends Human {

    private static final String MONEY = ".*?0100110101101111011011100110010101111001.*?";

    public String takeSides(String history) {
       return history != null && history.replace(",","").matches(MONEY) ? "evil" : "good";
    }
}
William Barbosa
la source
1
Ce vote ne jamais le mal s'il y a assez de participants, vous pouvez supprimer le ,hors history, encore plus que Rusher va diviser le jeu en groupe.
Angelo Fuchs
Je ne savais pas qu'il allait diviser le jeu en groupes. En fait, j'ai attendu que cette question ait suffisamment de propositions avant de poster ma réponse à cause de la taille de la chaîne. Merci de me le faire savoir.
William Barbosa
Si vous savez comment passer un argument de 60000 caractères à un processus Windows, faites-le moi savoir. Sinon, désolé de gâcher votre entrée et merci de l'avoir corrigée! Je n'avais pas prévu recevoir autant de soumissions.
Rainbolt
7

Le joueur fallacieux (Python)

Si une partie a remporté la majorité plusieurs fois d'affilée, le joueur se rend compte que l'autre partie risque davantage d'être la majorité au prochain tour (non?) Et cela influence son vote. Il vise la minorité, car s'il parvient à faire partie de la minorité, il y réussira probablement plusieurs fois (non?) Et accumulera beaucoup de points.

import sys
import random

def whoWon(round):
    return "good" if round.count("1") > round.count("0") else "evil"

if len(sys.argv) == 1:
    print random.choice(["good", "evil"])
else:
    history = sys.argv[1]
    rounds = history.split(",")
    lastWin = whoWon(rounds[-1])
    streakLength = 1
    while streakLength < len(rounds) and whoWon(rounds[-streakLength]) == lastWin:
        streakLength += 1
    lastLoss = ["good", "evil"]
    lastLoss.remove(lastWin)
    lastLoss = lastLoss[0] 
    print lastWin if random.randint(0, streakLength) > 1 else lastLoss  

Usage

Pour le premier tour:

python gambler.py

et ensuite:

python gambler.py 101,100,001 etc.
commando
la source
4
J'aime la façon dont vous semblez sûr de votre code, non? : P
IEatBagels
7

Automate cellulaire

Ceci utilise les règles conventionnelles du jeu de la vie de Conway pour choisir un camp. Tout d'abord, une grille 2D est créée à partir des votes précédents. Ensuite, le "monde" est avancé d'une étape et le nombre total de cellules vivantes restantes est calculé. Si ce nombre est supérieur à la moitié du nombre total de cellules, "bon" est choisi. Sinon, "le mal" est choisi.

S'il vous plaît pardonnez toutes les erreurs, cela a été écrasé pendant mon heure de déjeuner. ;)

package Humans;

public class CellularAutomaton extends Human {

    private static final String GOOD_TEXT = "good";

    private static final String EVIL_TEXT = "evil";

    private int numRows;

    private int numColumns;

    private int[][] world;

    @Override
    public String takeSides(String history) {
        String side = GOOD_TEXT;

        if (history.isEmpty()) {
            side = Math.random() <= 0.5 ? GOOD_TEXT : EVIL_TEXT;
        }

        else {
            String[] prevVotes = history.split(",");

            numRows = prevVotes.length;

            numColumns = prevVotes[0].length();

            world = new int[numRows][numColumns];

            for (int i = 0; i < numColumns; i++) {
                for (int j = 0; j < numRows; j++) {
                    world[j][i] =
                        Integer.parseInt(Character.toString(prevVotes[j].charAt(i)));
                }
            }

            int totalAlive = 0;
            int total = numRows * numColumns;
            for (int i = 0; i < numColumns; i++) {
                for (int j = 0; j < numRows; j++) {
                    totalAlive += getAlive(world, i, j);
                }
            }
            if (totalAlive < total / 2) {
                side = EVIL_TEXT;
            }
        }

        return side;
    }

    private int getAlive(int[][] world, int i, int j) {
        int livingNeighbors = 0;

        if (i - 1 >= 0) {
            if (j - 1 >= 0) {
                livingNeighbors += world[j - 1][i - 1];
            }
            livingNeighbors += world[j][i - 1];
            if (j + 1 < numRows) {
                livingNeighbors += world[j + 1][i - 1];
            }
        }
        if (j - 1 >= 0) {
            livingNeighbors += world[j - 1][i];
        }
        if (j + 1 < numRows) {
            livingNeighbors += world[j + 1][i];
        }
        if (i + 1 < numColumns) {
            if (j - 1 >= 0) {
                livingNeighbors += world[j - 1][i + 1];
            }
            livingNeighbors += world[j][i + 1];
            if (j + 1 < numRows) {
                livingNeighbors += world[j + 1][i + 1];
            }
        }

        return livingNeighbors > 1 && livingNeighbors < 4 ? 1 : 0;
    }
}
La théorie des graphes
la source
1
J'ai supprimé la ligne d'impression du code à des fins de test. Les entrées Java doivent seulement renvoyer le bien ou le mal, pas l'imprimer.
Rainbolt le
7

Le professeur de crête

J'espère que l'utilisation des bibliothèques est permise, ne vous sentez pas comme sans cela =)

L'idée de base est de former un classifieur de régression de crête pour chaque participant lors des derniers tours, en utilisant comme caractéristiques les 30 résultats avant chaque tour. À l’origine, le dernier tour de résultats était prévu pour tous les joueurs afin de prédire le résultat pour chaque joueur également, mais c’était assez serré pour le moment, lorsque le nombre de participants devient plus important (environ 50 environ).

#include <iostream>
#include <string>
#include <algorithm>
#include "Eigen/Dense"

using Eigen::MatrixXf;
using Eigen::VectorXf;
using Eigen::IOFormat;
using std::max;

void regress(MatrixXf &feats, VectorXf &classes, VectorXf &out, float alpha = 1) {
    MatrixXf featstrans = feats.transpose();
    MatrixXf AtA = featstrans * feats;

    out = (AtA + (MatrixXf::Identity(feats.cols(), feats.cols()) * alpha)).inverse() * featstrans * classes;
}

float classify(VectorXf &weights, VectorXf &feats) {
    return weights.transpose() * feats;
}

size_t predict(MatrixXf &train_data, VectorXf &labels, VectorXf &testitem) {
    VectorXf weights;
    regress(train_data, labels, weights);
    return (classify(weights, testitem) > 0 ? 1 : 0);
}

static const int N = 30;
static const int M = 10;
// use up to N previous rounds worth of data to predict next round
// train on all previous rounds available
size_t predict(MatrixXf &data, size_t prev_iters, size_t n_participants) {
    MatrixXf newdata(data.rows(), data.cols() + max(N, M));
    newdata << MatrixXf::Zero(data.rows(), max(N, M)), data;

    size_t n_samples = std::min(500ul, prev_iters);
    if (n_samples > (8 * max(N, M))) {
        n_samples -= max(N,M);
    }
    size_t oldest_sample = prev_iters - n_samples;
    MatrixXf train_data(n_samples, N + M + 1);
    VectorXf testitem(N + M + 1);
    VectorXf labels(n_samples);
    VectorXf averages = newdata.colwise().mean();
    size_t n_expected_good = 0;
    for (size_t i = 0; i < n_participants; ++i) {
        for (size_t iter = oldest_sample; iter < prev_iters; ++iter) {
            train_data.row(iter - oldest_sample) << newdata.row(i).segment<N>(iter + max(N, M) - N)
                                  , averages.segment<M>(iter + max(N, M) - M).transpose()
                                  , 1; 
        }
        testitem.transpose() << newdata.row(i).segment<N>(prev_iters + max(N, M) - N)
                  , averages.segment<M>(prev_iters + max(N, M) - M).transpose()
                  , 1;
        labels = data.row(i).segment(oldest_sample, n_samples);
        n_expected_good += predict(train_data, labels, testitem);
    }
    return n_expected_good;
}


void fill(MatrixXf &data, std::string &params) {
    size_t pos = 0, end = params.size();
    size_t i = 0, j = 0;
    while (pos < end) {
        switch (params[pos]) {
            case ',':
                i = 0;
                ++j;
                break;
            case '1':
                data(i,j) = 1;
                ++i;
                break;
            case '0':
                data(i,j) = -1;
                ++i;
                break;
            default:
                std::cerr << "Error in input string, unexpected " << params[pos] << " found." << std::endl;
                std::exit(1);
                break;
        }
        ++pos;
    }
}

int main(int argc, char **argv) {
    using namespace std;

    if (argc == 1) {
        cout << "evil" << endl;
        std::exit(0);
    }

    string params(argv[1]);
    size_t n_prev_iters = count(params.begin(), params.end(), ',') + 1;
    size_t n_participants = find(params.begin(), params.end(), ',') - params.begin();

    MatrixXf data(n_participants, n_prev_iters);
    fill(data, params);

    size_t n_expected_good = predict(data, n_prev_iters, n_participants);

    if (n_expected_good > n_participants/2) {
        cout << "evil" << endl;
    } else {
        cout << "good" << endl;
    }
}

Compiler

Enregistrez le code source dans un fichier appelé ridge_professor.cc, téléchargez la bibliothèque Eigen et décompressez le dossier Eigen situé dans le même dossier que le fichier source. Compiler avec g++ -I. -O3 -ffast-math -o ridge_professor ridge_professor.cc.

Courir

Appelez ridge_professor.exe et fournissez l'argument si nécessaire.

Question

Puisque je ne peux pas commenter pour le moment, je vais poser la question suivante: la limite de taille d'argument sur les fenêtres ne permet-elle pas d'appeler les fichiers binaires résultants avec l'historique complet à quelques centaines de tours? Je pensais que l'argument ne pouvait pas contenir plus de 9 000 caractères ...

dgel
la source
Merci d'avoir attiré mon attention sur ceci . Je vais trouver un moyen de le faire fonctionner si cela ne fonctionne pas déjà bien en Java. Si Java ne peut pas le faire, la recherche me dit que le C ++ le peut, et j'en profiterai pour le réapprendre. Je serai de retour sous peu avec les résultats des tests.
Rainbolt
Comme il s'avère, Java n'est pas soumis aux limitations de l'invite de commande. Il semble que seules les commandes supérieures à 32 Ko posent un problème. Voici ma preuve (je l'ai écrite moi-même): docs.google.com/document/d/… . Encore une fois, j'apprécie beaucoup que vous souleviez cette question avant le début des procès demain.
Rainbolt
@Rusher Il y a déjà 57 robots et vous prévoyez que chaque manche sera composé de 1000 tours. Cela ferait de votre chaîne 57k caractères (donc> 32k), n'est-ce pas?
Plannapus
1
@Rusher Je pense qu'il serait peut-être préférable de prolonger la chronologie d'une semaine supplémentaire et de demander aux participants de modifier leurs programmes pour lire stdin au lieu d'utiliser une chaîne d'arguments. Ce serait trivial pour la plupart des programmes de changer
dgel
@dgel La chronologie du défi est infiniment longue, mais je ne veux pas changer les règles de manière à ce que tout le monde soit obligé de réécrire sa réponse. Je suis à peu près sûr que la règle que j'ai ajoutée hier soir ne ferait que gâcher une seule soumission, et je compte aider cette personne si jamais il parvient à ce que son programme soit complet.
Rainbolt
6

Crowley

Parce que les Winchesters sont beaucoup moins intéressants sans ce type. Il est évident qu'il se range du côté du mal… à moins que cela ne soit nécessaire pour prendre soin d'un plus grand mal.

package Humans;

public class Crowley extends Human {
public String takeSides(String history) {
    int gd = 0, j=history.length(), comma=0, c=0, z=0;
    while(comma < 2 && j>0)   {
        j--;
        z++;
        if (history.charAt(j) == ',') {
            comma++;
            if(c> z/2) {gd++;}
            z=0;
            c=0;
        } else if (history.charAt(j)=='1') {
            c++;
        } else {
        }
    }
    if(gd == 0){
        return "good";
    } else {
        return "evil";
    }
}}

Je regarde les deux derniers tours (0 virgule jusqu'à présent et 1 virgule jusqu'à présent) et si les deux laissaient le mal gagner, je votais bien. Sinon, je vote le mal.

Kaine
la source
Est-ce que je comprends bien? Vous regardez le dernier tour et si moins de 50% sont des "bons" votes, vous êtes du "bon" sinon du mal? (Par curiosité: Préférez-vous les noms de variables cryptiques ou s'agit-il d'un accident?)
Angelo Fuchs
1
@ AngeleloNeuschitzer Je regarde les deux derniers tours (0 virgule jusqu'à présent et 1 virgule jusqu'à présent) et si les deux laissaient le mal gagner, je votais bien. Sinon, je vote le mal. Je préfère les noms de variables qui sont courts à taper si le code est suffisamment court pour que le but du code ne soit pas confus. Je ne suis pas un programmeur professionnel et c'était la première fois que je programmais en Java ou quelque chose d'autre voyait le code depuis 6 ans et demi. J'ai écrit ceci pour me rafraîchir la mémoire. (TLDR, ils ne sont pas cryptiques pour moi et je suis le seul pour
lequel
Pour plus de clarté ... Crowley a commencé comme un être humain, donc c'était intentionnel, il commence bien ... Je ne m'attendais pas à ce qu'il reste bon pour toutes les épreuves ... putain
kaine