Gut gegen Böse

112

Ergebnisse - 19. Juli 2014

Der aktuelle King of the Hill ist Mercenary von User Fabigler ! Reichen Sie weiterhin Einträge ein und stoßen Sie ihn von seinem Thron!

Klicken Sie hier, um die Anzeigetafel anzuzeigen.

Programme, die am oder vor dem 19. Juli 2014 eingereicht wurden, wurden berücksichtigt. Alle anderen Einsendungen werden in zukünftigen Versuchen berücksichtigt. Neue Ergebnisse sollten um den 9. August veröffentlicht werden, damit Sie genügend Zeit haben.


Illustration gezeichnet vom Bruder Illustriert von Chris Rainbolt, meinem Bruder und einem frisch gebackenen Absolventen des Savannah College of Art and Design

Einführung

Die Engel und Dämonen kämpfen und benutzen wie gewöhnlich die Erde als Schlachtfeld. Die Menschen sitzen in der Mitte fest und werden gezwungen, Partei zu ergreifen. Eine unbekannte neutrale Kraft belohnt diejenigen, die konsequent für die Verliererseite kämpfen.

Das Spiel

Bei jedem Versuch werden Sie pseudozufällig gepaart und anschließend mit 20 bis 30 anderen Einsendungen gemischt. Jeder Versuch besteht aus 1000 Runden. In jeder Runde erhalten Sie eine Eingabe und es wird erwartet, dass Sie eine Ausgabe erzeugen. Ihre Ausgabe wird aufgezeichnet und bewertet. Dieser Vorgang wird 1000 Mal wiederholt.

Eingang

Sie erhalten ein einzelnes Argument, das die vergangenen Stimmen jedes Spielers darstellt. Runden werden durch Komma getrennt. A steht 0für einen Spieler, der in dieser Runde auf der Seite des Bösen stand. A steht 1für einen Spieler, der auf der Seite von Gut steht. Innerhalb eines Versuchs werden die Spieler immer in der gleichen Reihenfolge sein. Ihre eigene Stimme wird aufgenommen, aber nicht explizit identifiziert. Zum Beispiel:

101,100,100

In diesem Beispiel wurden drei Runden abgeschlossen und drei Spieler treten gegeneinander an. Spieler eins stand immer auf der Seite des Guten. Spieler zwei war immer auf der Seite des Bösen. Spieler drei wechselte in Runde 1 von Gut zu Böse in Runde 2 und 3. Einer dieser Spieler warst du.

Ausgabe

Java-Einreichungen

  • Geben Sie den String zurück, goodwenn Sie auf der Seite von Good stehen möchten.
  • Gib den String zurück, evilwenn du mit Evil auf der Seite stehen willst.

Nicht-Java-Beiträge

  • Geben Sie den String goodauf stdout aus, wenn Sie auf der Seite von Good stehen möchten.
  • Geben Sie die Zeichenfolge evilauf stdout aus, wenn Sie auf der Seite des Bösen stehen möchten.

Wenn Ihr Programm etwas anderes ausgibt oder zurückgibt, eine Ausnahme auslöst, nicht kompiliert oder länger als eine Sekunde benötigt, um etwas auf diesem Computer auszugeben , wird es disqualifiziert.

Wertung

Die Ergebnisse werden in einer Google Text & Tabellen-Tabelle zur einfachen Anzeige veröffentlicht, sobald ich alle aktuellen Einträge zusammenstellen kann. Keine Sorge, ich werde so lange Tests durchführen, wie ihr Programme einreicht!

  • Sie erhalten 3 Punkte, wenn Sie sich in einer Runde mit der Mehrheit abfinden.
  • Sie erhalten n - 1 Punkte, wenn Sie in einer Runde auf der Seite der Minderheit stehen, wobei n die Anzahl der aufeinanderfolgenden Male ist, die Sie auf der Seite der Minderheit stehen.

Ihre Punktzahl wird der Median von 5 Versuchen sein. Jeder Versuch besteht aus 1000 Runden.

Liefergegenstände

Nicht-Java-Beiträge

Sie müssen einen eindeutigen Titel, ein Programm und eine Windows-Befehlszeilenzeichenfolge übergeben, mit der Ihr Programm ausgeführt wird. Denken Sie daran, dass ein Argument an diese Zeichenfolge angehängt werden kann. Zum Beispiel:

  • python Angel.py
    • Beachten Sie, dass dieser keine Argumente hat. Das ist die erste Runde! Seien Sie darauf vorbereitet.
  • python Angel.py 11011,00101,11101,11111,00001,11001,11001

Java-Einreichungen

Sie müssen einen eindeutigen Titel und eine Java-Klasse einreichen, die die unten beschriebene abstrakte Human-Klasse erweitert.

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

Testen

Wenn Sie Ihren eigenen Beitrag testen möchten, befolgen Sie die Anweisungen hier .

Zusätzliche Bemerkungen

Sie können so viele verschiedene Beiträge einreichen, wie Sie möchten. Einsendungen, die als Absprachen erscheinen, werden disqualifiziert. Der Autor dieser Herausforderung wird der einzige Richter in dieser Angelegenheit sein.

Bei jedem Aufruf wird eine neue Instanz Ihres Programms oder Ihrer Java-Klasse erstellt. Sie können Informationen beibehalten, indem Sie in eine Datei schreiben. Sie dürfen die Struktur oder das Verhalten von nichts außer Ihrer eigenen Klasse ändern.

Die Spieler werden vor Beginn der Testphase gemischt. Demon und Angel werden an jeder Prüfung teilnehmen. Wenn die Anzahl der Spieler gerade ist, schließt sich auch Petyr Baelish an. Demon kämpft für das Böse, Angel für das Gute und Petyr Baelish wählt eine pseudozufällige Seite.

Regenblitz
quelle
2
Kommentare wurden gelöscht, da sie veraltet waren und auf Anfrage von OP. Bitte benachrichtigen Sie mich über alle Kommentare, die wiederhergestellt werden müssen.
Türklinke
7
Woah, OP ändert seinen Benutzernamen. Ok, wann wird das Ergebnis angezeigt?
Nur die Hälfte des
6
@Rainbolt Das muss eine verdammt verdammte Aufgabe sein, diese Herausforderung zu meistern! Der Grund für diese Aufmerksamkeit ist die Einfachheit des Protokolls und der Regeln, die es zugänglich machen und gleichzeitig einfache, funktionierende Einträge ermöglichen. TL; DR: Deine Herausforderung ist zu gut! : D
Tomsmeding
3
@dgel Ich werde die Rohdaten, den oberen, den unteren, den Durchschnitt und vielleicht ein Liniendiagramm veröffentlichen, damit wir sehen können, wer im Zuge der Konkurrenz besser abschneidet.
Rainbolt
6
Einer der Pods endete mit 10 Einsendungen, die jedes Mal auf die gleiche Weise stimmten. Infolgedessen erzielten zwei Benutzer perfekte oder "eine Runde weniger als perfekt" Ergebnisse von rund 450.000. Die gleichen Einträge erzielten um 1900 in anderen Versuchen. Die durchschnittliche Punktzahl liegt in der Nähe von 2000. Aufgrund des extremen Ungleichgewichts bei den Ergebnissen entschied ich, dass eine aussagekräftigere Zahl ein Median wäre. Ich habe die Herausforderung so bearbeitet, dass nach 5 Versuchen der Gewinner der Beitrag mit dem höchsten Median ist. Wenn jemand der Meinung ist, dass der Übergang vom Mittelwert zum Median unfair oder auf andere Weise eine schlechte Wahl ist, kommentieren Sie dies bitte.
Rainbolt

Antworten:

11

Der Söldner

Immer auf der Seite desjenigen, der in der letzten Runde das meiste Geld bezahlt hat.

Unter Berücksichtigung, dass gute Leute statistisch mehr verdienen.

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
quelle
2
Dies ist der zweite Beitrag , der etwas über Geld aussagt. Fehlt mir eine Referenz oder so?
Rainbolt
Stimmt, aber dieser Typ ist ein noch böserer Bastard. Jede Runde seine Freunde im Stich lassen, nur um Geld zu sparen.
Fabigler
In Ihrer switch-Anweisung fehlte eine return-Anweisung für den Standardfall, sodass sie nicht kompiliert werden konnte. Ich habe eine zufällige hinzugefügt.
Rainbolt
4
Herzlichen Glückwunsch, König des Hügels! Ich verstehe nicht, wie dieser Eintrag gewinnt. Möchtest du eine Erklärung hinzufügen, jetzt, wo eine Reputationsprämie von 300 damit verbunden ist?
Rainbolt
4
Möglicherweise ein Fehler, oder ich habe die Kommentare und die Beschreibung falsch verstanden, aber der Söldner tut nicht wirklich das, was er wollte. Mit Ausnahme der ersten zufälligen Runde steht er immer auf der Seite des Bösen, es sei denn, weniger als 1/6 der Menschen haben in der vorherigen Runde für das Böse gestimmt.
Jaybz
39

Hipster, Ruby

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

Geht einfach mit der Minderheit der letzten Runde, nur weil alles andere Mainstream ist.

Laufen wie

ruby hipster.rb
Martin Ender
quelle
30

Petyr Baelish

Man weiß nie, auf wessen Seite Petyr Baelish steht.

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

Dieser Eintrag wird nur berücksichtigt, wenn die Anzahl der Spieler gerade ist. Dies stellt sicher, dass es immer eine Mehrheit gibt.

Regenblitz
quelle
28
Offensichtlich auf Petyr Baelishs Seite.
Cthulhu
2
@ Kevin Es schlägt durchweg die meisten Bots. Normalerweise erreicht es 27ish.
cjfaure
3
@Kevin Dieser Eintrag wurde vom Autor der Challenge eingereicht. Das sollte nicht gut gehen. Es ist dafür zu sorgen, dass es immer eine Mehrheit gibt, denn bei einer geraden Anzahl von Spielern könnte es zu einem Unentschieden kommen.
Rainbolt
4
Warum, oh Gott, warum hat dieser die meisten Stimmen? Es ist einfach nicht fair .
Tomsmeding
3
@ Tomsmeding Nein. Es ist ein Zitat aus Game of Thrones lol.
Rainbolt
29

C ++, der Metawissenschaftler

Dieser macht im Wesentlichen dasselbe wie The Scientist, wirkt sich jedoch nicht auf Runden als Ganzes aus, sondern auf die einzelnen Spieler. Es versucht, jedem Spieler separat eine Welle (oder eine konstante Funktion) zuzuordnen, und prognostiziert seinen Zug in der nächsten Runde. Aus der resultierenden Prognose wählt The Meta Scientist, welche Seite eine Mehrheit zu haben scheint.

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

Wenn Sie Debug-Anweisungen aktivieren möchten, ändern Sie die Zeilenlesung #if 0in #if 1.

Kompiliere mit g++ -O3 -std=c++0x -o MetaScientist MetaScientist.cpp(du brauchst keine Warnungen, also nein -Wall) und starte mit MetaScientist.exe(möglicherweise natürlich auch mit dem Argument). Wenn Sie wirklich nett fragen, kann ich Ihnen eine ausführbare Windows-Datei zur Verfügung stellen.

EDIT: Anscheinend lief die Vorgängerversion rund 600 Runden aus. Das sollte das nicht tun. Sein Zeitverbrauch wird von der #define WINDOW (...)Leitung gesteuert , mehr ist langsamer, schaut aber weiter zurück.

Tomsmeding
quelle
2
Ich schlage demütig vor, dass Sie versuchen, die Verliererseite zu wählen. Wenn Sie konsequent richtig raten können, erhalten Sie mehr als 3 Punkte pro Runde.
Kevin
1
@ Kevin Das ist wahr, aber ich dachte mir, dass es ziemlich schnell die falsche Seite erraten könnte, und Sie müssen die verlierende Seite mehr als sieben Mal hintereinander richtig erraten, um eine Verbesserung zu erzielen, indem Sie immer die Mehrheit richtig machen. Ich könnte es aber ändern.
Tomsmeding
1
@ Kevin Außerdem würde ich gerne zuerst sehen, wie sich diese (Wissenschaftler und Meta-Wissenschaftler) verhalten, wenn Rusher uns an diesem Wochenende eine Anzeigetafel besorgt, wie er in den Kommentaren zum OP angedeutet hat. Rusher, sorry, aber ich bin zu faul, um alles selbst zusammenzustellen ... :)
tomsmeding
3
Keine Bange! Es ist wahrscheinlich sowieso nicht sicher, diese auszuführen. Lassen Sie mich einfach meinen Computer mit Code vermasseln, der von 50 Fremden im Internet geschrieben wurde.
Rainbolt
1
@ Kevin Aber das ist so VIEL ! Ich kann zwar, aber ich mag es nicht. Ich werde sehen, wie es diesen geht.
Tomsmeding
26

Engel

Der reinste Spieler von allen.

Programm

print "good"

Befehl

python Angel.py
Regenblitz
quelle
22
Python ist eine gute Sprache. Es scheint nur natürlich, dass der Engel es benutzen sollte.
jpmc26
23
Darf ich die Leute daran erinnern, dass eine Python eine Schlange ist. Eine Schlange.
Mr Lister
3
@MrLister Darf ich Sie daran erinnern, dass Luzifer ein großer Engel war, bevor Gott ihn vom Himmel geworfen hat?
Zibbobz
1
@ Zibbobz Ja ... wirklich schade, dass sie rausgefallen sind. Sie hätten zusammen so viel erreichen können.
Mr 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";
           }
        }
    }
}

In Buch 7, The Atlantis Complex , erkrankte Artemis Fowl an einer psychischen Erkrankung (genannt Atlantis Complex), die ihn zwang, alles in Vielfachen von 5 zu tun (Sprechen, Handeln usw.). Als er es in einem Vielfachen von 5 nicht schaffen konnte, geriet er in Panik. Ich mache im Grunde das: Sehen Sie, ob Gut oder Böse (Vorspannung) durch 5 teilbar ist, wenn beides nicht der Fall ist, dann gerate ich in Panik und sehe, was größer war und laufe mit dieser oder Panik noch weiter und wähle zufällig.

Kyle Kanos
quelle
4
Als ich Artemis Fowl in der Mittelstufe las, existierten nur zwei Bücher. Es ist schön zu sehen, dass es jetzt sieben sind und dass Disney es in einen Film verwandelt.
Rainbolt
1
Es gibt tatsächlich 8 Bücher.
Kyle Kanos
7
Je mehr desto besser (es sei denn, Sie lesen das Rad der Zeit)
Rainbolt
1
Und du hast break;in deinem vergessen switch.
Johnchen902
1
@ johnchen902, @ Manu: Ich bin nicht sehr erfahren in Java (ich benutze Fortran90 + & sehe nur Java hier), daher meine Fehler. Ich repariere sie, wenn ich in einer Stunde im Büro bin.
Kyle Kanos
19

Disparnumerophobic

Ungerade Zahlen sind erschreckend.

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";
    }
}
Pseudonym117
quelle
17
Kommentar brachte mich zum Lachen / Schnauben.
Phyrfox
17

Linus, Rubin

Versucht, Analysten zu verwirren, indem immer das Muster gebrochen wird .

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

Speichern unter linus.rbund starten mitruby linus.rb

Histokrat
quelle
16

Der BackPacker

Bestimmt einen Spieler, der die passende Minderheit am meisten gewählt hat, und wählt seine letzte Stimme.

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

Der CrowdFollower

Bestimmt einen Spieler, der die passende Mehrheit gewählt hat und wählt seine letzte Stimme.

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
quelle
Sehr sauberes Programm!
Rainbolt
Hoppla, ich glaube, ich habe Ihr Programm möglicherweise in einer anderen Sprache kopiert.
PyRulez
@ Rusher Ich habe den Code aktualisiert und möchte diesen als zwei Einträge hinzufügen, einen mit goWithMajority = trueund einen wo er ist false. Ist das in Ordnung oder muss ich dafür einen zweiten BackPacker hinzufügen?
Angelo Fuchs
@AngeloNeuschitzer Ich habe diesen Beitrag bearbeitet. Auf diese Weise werde ich nicht vergessen, beide Einsendungen hinzuzufügen. Ich schlage vor, Sie ändern den wirklich unkreativen Namen, den ich ihm gegeben habe, und fügen möglicherweise eine Beschreibung zu beiden hinzu, wenn Sie möchten.
Rainbolt
1
@Rainbolt Ihr FrontPacker gefällt mir eigentlich besser. Lol'd.
Tomsmeding
15

Wahrsager

Dies ist noch in Arbeit. Ich habe es noch nicht getestet. Ich wollte nur sehen, ob das OP denkt, dass es gegen die Regeln verstößt oder nicht.

Die Idee ist, die nächste Runde zu simulieren, indem alle anderen Teilnehmer einige Male ausgeführt werden, um eine Wahrscheinlichkeit für das Ergebnis zu erhalten und entsprechend zu handeln.

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
quelle
Wenn Ihr Bot vor der Beantwortung alle anderen Bots in jeder Runde ausführt, dauert die Beantwortung dann nicht länger als eine Sekunde?
Plannapus
@plannapus Ich gehe davon aus, dass bei diesem Bot alle anderen auf Nummer sicher gehen und alles Warten vermeiden, das knapp 1 Sekunde dauert. Ich denke, es kann sich lohnen, einen Beitrag einzureichen, der aus einer Wartezeit von 0,9 Sekunden besteht, bevor Sie "gut" zurückkehren, nur um sich mit ihm anzufreunden. Eigentlich hat mich SBoss geschlagen: D
scragar
Yahhh! Dann müsste ich diesen Bot in meinem Code auf die schwarze Liste setzen. Das wäre frustrierend ... Auch bei unterschiedlichen Einträgen in unterschiedlichen Umgebungen wie Python oder Perl könnte das erneute Laden des Interpreters ausreichen, um diesen Code über das Zeitlimit zu bringen.
Andris
16
Wenn jemand anderes dasselbe tut, erhalten Sie eine Endlosschleife.
Brilliand
4
Die Einreichung ist abgelaufen. Ich habe einen Profiler angehängt und fast eine halbe Sekunde damit verbracht, einige Einreichungen aufzurufen. Zumindest funktioniert es, also herzlichen Glückwunsch.
Rainbolt
15

C ++, der Wissenschaftler

Dieser versucht, mit der Geschichte dessen, was die Mehrheit pro Runde gewählt hat wave( majority()gibt der Mehrheit die Wahl in einer Runde), eine Welle an die Daten von Wellenlänge 2*periodund Phase anzupassen phase. Wenn 0,1,1,1,0,1,0,1,1,1,0,0,0,1,0es also period=3, phase=5( maxat=={3,5}) auswählt, werden seine Ergebnisse 9 3 11 5 5 3 5 7 9 7 7 7 7 7 7. Es durchläuft alle möglichen Zeiträume und speichert, wenn für diesen Zeitraum die Punktzahl höher ist als für das aktuelle Maximum, {period,phase}für welches es aufgetreten ist.

Anschließend wird die gefundene Welle in die nächste Runde extrapoliert und die vorhergesagte Mehrheit übernommen.

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

Kompiliere mit g++ -O3 -std=c++0x -o Scientist Scientist.cpp(du brauchst keine Warnungen, also nein -Wall) und starte mit Scientist.exe(möglicherweise natürlich auch mit dem Argument). Wenn Sie wirklich nett fragen, kann ich Ihnen eine ausführbare Windows-Datei zur Verfügung stellen.

Oh, und wage es nicht, mit dem Eingabeformat herumzuspielen. Es wird sonst seltsame Dinge tun.

EDIT: Anscheinend lief die Vorgängerversion rund 600 Runden aus. Das sollte das nicht tun. Sein Zeitverbrauch wird von der #define WINDOW (...)Leitung gesteuert , mehr ist langsamer, schaut aber weiter zurück.

Tomsmeding
quelle
8
Das Herunterladen von ausführbaren Dateien, die von über sechzig Fremden im Internet geschrieben wurden, scheint eine schlechte Idee zu sein.
Rainbolt
@Rusher da stimme ich voll und ganz zu. Wenn Sie Probleme haben möchten, ist dies der erste Schritt in der Anleitung "Für Dummies". Mein Angebot steht aber :)
Tomsmeding
2
Habe dieses gut zu kompilieren (und zu konkurrieren).
Rainbolt
14

Code Runner

Um die Sache interessant zu machen, habe ich ein Skript erstellt, mit dem der Code aus jeder veröffentlichten Antwort automatisch heruntergeladen, bei Bedarf kompiliert und dann alle Lösungen gemäß den Regeln ausgeführt werden. Auf diese Weise können die Leute überprüfen, wie es ihnen geht. Speichern Sie dieses Skript einfach in run_all.py (erfordert BeautifulSoup) und dann:

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

Ein paar Dinge:

  1. Wenn Sie Unterstützung für weitere Sprachen hinzufügen oder die Unterstützung für einige Sprachen entfernen möchten, lesen Sie def submission_type(lang).
  2. Das Erweitern des Skripts sollte auch für Sprachen, die kompiliert werden müssen, relativ einfach sein (siehe CPPSubmission). Der Sprachtyp wird aus dem Meta-Code-Tag < !-- language: lang-java -- >abgerufen. Fügen Sie ihn daher hinzu, wenn der Code ausgeführt werden soll. (Entfernen Sie die zusätzlichen Leerzeichen vor und nach dem <>.) UPDATE : Es gibt jetzt einige äußerst grundlegende Schlussfolgerungen, um zu versuchen, die Sprache zu erkennen, wenn sie nicht definiert ist.
  3. Wenn Ihr Code nicht ausgeführt werden kann oder nicht innerhalb der festgelegten Zeit fertig ist, wird er blacklist.textautomatisch zu zukünftigen Tests hinzugefügt und aus diesen entfernt. Wenn Sie Ihren Code korrigieren, entfernen Sie einfach Ihren Eintrag von der Blacklist und führen Sie ihn erneut aus get.

Derzeit unterstützte Sprachen:

 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
}

Ohne weiteres:

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
Was für eine Welt
quelle
Warum keine Fortran Sprache ?
Kyle Kanos
@KyleKanos - Ich habe Unterstützung hinzugefügt, werde den Code in Kürze aktualisieren.
WhatAWorld
Yay! Ich (irgendwie) habe hart an meinem Fortran-Beitrag gearbeitet und Rusher kann ihn nicht zum Laufen bringen, also würde ich gerne jemand es bekommt :)
Kyle Kanos
1
@Rusher: Da stimme ich PeterTaylor zu: Syntax-Hervorhebung, da die einzige vorgeschlagene Änderung abgelehnt werden sollte. Änderungen sollten für wesentliche Korrekturen verwendet werden , nicht für kleinere Dinge.
Kyle Kanos
1
Sie haben den Repräsentanten dafür verdient, aber da dies nicht genau die Antwort auf die Frage ist (und wahrscheinlich davon profitieren könnte, dass die Community Sachen für andere Sprachen hinzufügt), denke ich, dass dies technisch gesehen ein Community-Wiki sein sollte.
Martin Ender
13

Der schöne Geist, Rubin

Trifft seine Entscheidung auf der Grundlage von Mustern von fraglicher Bedeutung in der Bitdarstellung der letzten Runde

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

Laufen wie

ruby beautiful-mind.rb
Martin Ender
quelle
13

Gierig, Lua

Ein abergläubisches Programm, das an Zeichen und Wunder glaubt.

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

starte es mit:

lua Piustitious.lua

gefolgt von der Eingabe.

AndoDaan
quelle
11

Die Winchesters

Sam und Dean sind gut (die meiste Zeit).

package Humans;

public class TheWinchesters extends Human {

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

}
CommonGuy
quelle
Sind Sie sicher, dass 9:1das richtige Verhältnis vorliegt? Vielleicht sollten wir Data Mining durchführen und ein genaueres Verhältnis erhalten?
Rekursion.ninja
1
@awashburn Ich habe vor 2 Monaten angefangen, Supernatural anzuschauen (steckte jetzt in Staffel 9 fest) und 9:1scheint mir in
Ordnung
10

Statistiker

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";
    }
}
Unverdient
quelle
5
Diese vorletzte Zeile ist so fantastisch
cjfaure
5
@Undeserved Anstelle von Math.ceil(Math.random()-Math.random())dir kannst du auch einfach machen Math.round(Math.random()).
Tomsmeding
10

R, ein etwas bayesianischer Bot

Verwenden Sie die Häufigkeitstabelle für jeden Benutzer als vorherige Wahrscheinlichkeit für die Ausgabe anderer Benutzer.

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

Wird mit Rscript BayesianBot.Rgefolgt von der Eingabe aufgerufen .

Bearbeiten : Nur um zu verdeutlichen, was dies tut, ist hier ein Schritt für Schritt mit der Beispieleingabe:

> 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

Dann result<-wählt die Linie , die mit jedem Spieler beginnt , nach dem Zufallsprinzip entweder 0 oder 1 aus, wobei diese letzte Tabelle als Gewichtung verwendet wird (dh für Spieler 1 beträgt die Wahrscheinlichkeit, 0 zu wählen, 2/7, 1 5/7 usw.). Es wird ein Ergebnis für jeden Spieler / jede Spalte ausgewählt und schließlich die Zahl zurückgegeben, die am häufigsten vorkommt.

Plannapus
quelle
10

schweizerisch

Bewahrt immer Neutralität. Zum Scheitern verurteilt, niemals zu gewinnen.

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
quelle
Ich habe das nicht geschrieben!
Rainbolt
Das ist die Ironie. Neutralität gewinnt nie
fabigler
2
@ Rusher ah ich habe es jetzt: D
Fabigler
1
Es wird nicht einmal kompiliert - es fehlt ein Semikolon.
Paŭlo Ebermann
9

HAL 9000

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

Bearbeiten: Vielleicht ist dies besser für HAL 9000 geeignet, aber seien Sie vorsichtig! Es ist sehr böse. Ich empfehle cd, das Verzeichnis vor dem Ausführen zu leeren.

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

Dies entfernt eine Datei cwdfür jeden Aufruf!

Nicht so offensichtliche Anrufung:

In M $

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

D:>hal_9000.pl
evil

In * 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
quelle
Sie müssen einen Befehl angeben, mit dem Sie Ihr Programm ausführen können. Weitere Informationen finden Sie im Abschnitt "Leistungen" der Herausforderung.
Rainbolt
@ Rusher Fertig;)
Core1024
9

Wille der Mehrheit

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

Speichern Sie es als WotM.py , führenpython3 WotM.py von der Eingabe gefolgt aus.

Ein einfaches Programm, um zu sehen, wie es funktioniert. Passt zu allem, was die Mehrheit beim letzten Mal gesagt hat, oder auch zufällig.

isaacg
quelle
Sie müssen einen Befehl angeben, mit dem Sie Ihr Programm ausführen können. Weitere Informationen finden Sie im Abschnitt "Leistungen" der Herausforderung.
Rainbolt
Verdammt, das macht meins zu einem Duplikat. : D Meins wurde in eine Minderheit umgewandelt.
Martin Ender
@Rusher Befehl hinzugefügt. Das, wonach du gesucht hast?
Isaacg
@isaacg Perfekt!
Rainbolt
1
Ich habe den Durchschnittsrang anhand der Punktzahlen in der Anzeigetafel berechnet, und dieser Eintrag gewinnt mit dieser Kennzahl.
Brilliand
9

Alan Shearer

Wiederholt, was auch immer die Person, neben der er sitzt, gerade gesagt hat. Wenn sich herausstellt, dass die Person falsch liegt, wechselt sie zur nächsten Person und wiederholt stattdessen, was sie sagt.

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
quelle
Sie referenzieren eine aufgerufene Variable, lastRoundbevor Sie sie deklarieren. Außerdem haben Sie allen Klammern hinzugefügt String.length, dies ist jedoch keine Funktion. Können Sie Ihre Einreichung an einen Punkt bringen, an dem sie kompiliert wird?
Rainbolt
@ Rusher - fertig :)
Algy Taylor
@Algy: lastRound.lengthwird immer noch angesprochen (im ersten if), bevor lastRounddeklariert wird (in diesem if's else). Bitte versuchen Sie, Ihren Code zu kompilieren (und möglicherweise auszuführen), bevor Sie ihn hier einreichen.
Paŭlo Ebermann
@ PaŭloEbermann - Entschuldigung, ich bin nicht in einer Umgebung, in der ich es ausführen kann - Änderung gemacht, aber
Algy Taylor
Jetzt verweisen Sie auf eine Variable namens "personToCopy", wenn sie außerhalb des Gültigkeitsbereichs liegt. Ich habe es einfach in den else-Block verschoben, damit es kompiliert werden kann, aber ich weiß nicht, ob Sie das wollten.
Rainbolt
8

Später ist Evil, JavaScript ( node.js )

Misst die Zeit zwischen den Ausführungen. Wenn der Zeitunterschied größer ist als beim letzten Mal, muss es böse sein. Ansonsten gut.

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

Laufen mit: node laterisevil.js

nderscore
quelle
8

Pattern Finder, Python

Sucht nach einem wiederkehrenden Muster, und wenn es eines nicht findet, passt es einfach zur Mehrheit.

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

renn mit

python3 pattern_finder.py
CaesiumLifeJacket
quelle
1
Ich liebe diesen Code so sehr, wenn ich ihn ausführe, bekomme ich irgendwie immer 3000 Punkte.
Realdeo
8

Der Turncoat

Der Turncoat glaubt, dass wegen der anderen Kämpfer die Mehrheit nach jeder Runde öfter zwischen Gut und Böse wechselt, als auf der gleichen Seite zu bleiben. So beginnt er die erste Runde, indem er sich willkürlich für gut einsetzt, und wechselt dann jede Runde, um häufiger im siegreichen oder verlorenen Team zu bleiben.

package Humans;

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

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

Nachdem ich dies geschrieben hatte, wurde mir klar, dass aufgrund der Einträge, die auf statistischen Analysen basierten, die Mehrheit aufgrund der Dynamik weniger die Seite wechseln würde, wenn mehr Runden abgeschlossen waren. Daher der Lazy Turncoat.

Der faule Mantel

Der Lazy Turncoat startet wie der Turncoat, aber als die Runden vorbei sind, wird er immer fauler, um auf die andere Seite zu wechseln.

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
quelle
2
Der Lazy Turncoat ist großartig!
Angelo Fuchs
Ich schließe beides ein, wenn es Ihnen nichts ausmacht.
Rainbolt
Gehen Sie geradeaus. Ich bin gespannt, wie sich beide entwickeln werden, insbesondere im Vergleich zu denen, die Abstimmungsstatistiken erstellen.
Jaybz
@Rainbolt Ich habe gerade einen dummen Fehler mit dem Turncoat bemerkt. Keine Notwendigkeit, es zu korrigieren. Es funktioniert immer noch, nur nicht ganz wie beabsichtigt, und selbst wenn es nicht zu spät ist, um es zu reparieren, wird es sich trotzdem genauso verhalten wie einer der neueren Einträge, wenn es repariert wird. Fühlen Sie sich frei, ein- oder auszuschließen, wenn Sie möchten.
Jaybz
8

Biograf, Rubin

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]

Mein Versuch eines fast intelligenten Eintrags (ein wirklich intelligenter würde das Testen gegen das Feld erfordern). Geschrieben in Ruby, daher besteht die Möglichkeit, dass dies zu langsam ist, aber auf meinem Rechner dauert es trotzdem 0,11 Sekunden, um die letzte Runde zu berechnen, wenn 40 zufällige Spieler anwesend sind. Ich hoffe, dass es gut genug funktioniert.

Speichern unter biographer.rb, Ausführen alsruby biographer.rb

Die Idee ist, dass für jeden Spieler seine Chancen, "gut" zu werden, geschätzt werden, indem sowohl seine eigenen Entscheidungen für die letzten zehn Runden als auch die Gesamtergebnisse betrachtet werden und Beispiele in der Vergangenheit gefunden werden, in denen die gleichen Umstände (ihre Stimmen + insgesamt) vorliegen Ergebnisse) aufgetreten. Es wählt die längste Lookbehind-Länge aus, bis zu 10 Runden, so dass es einen Präzedenzfall gibt, und verwendet diese, um eine Frequenz zu erstellen (angepasst gemäß Laplace-Gesetz der Nachfolge, sodass wir uns nie zu 100% sicher sind).

Anschließend werden einige Simulationen ausgeführt und es wird angezeigt, wie oft Good gewinnt. Wenn die Simulationen größtenteils auf die gleiche Art und Weise verlaufen sind, ist es wahrscheinlich gut, Vorhersagen im Allgemeinen zu treffen, sodass die vorhergesagte Minderheit ausgewählt wird. Wenn es nicht sicher ist, wählt es die vorhergesagte Mehrheit.

Histokrat
quelle
8

Judas

Judas ist ein wirklich guter Mensch. Schade, dass er die Guten für ein paar Cent verraten wird.

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
quelle
1
Dies stimmt immer nur das Böse , wenn es genügend Teilnehmer, Sie entfernen möchten ,aus history, umso mehr, als Rusher das Spiel in Gruppen aufgeteilt wird.
Angelo Fuchs
Ich wusste nicht, dass er das Spiel in Gruppen aufteilen würde. Ich habe tatsächlich darauf gewartet, dass diese Frage genügend Eingaben enthält, bevor ich meine Antwort aufgrund der Zeichenfolgengröße veröffentliche. Danke für die Information.
William Barbosa
Wenn Sie wissen, wie ein 60000-Zeichen-Argument an einen Prozess in Windows übergeben wird, lassen Sie es mich wissen. Ansonsten entschuldige, dass du deinen Eintrag durcheinander gebracht hast, und danke, dass du ihn repariert hast! Ich habe nicht mit so vielen Einsendungen gerechnet.
Rainbolt
7

Der trügerische Spieler (Python)

Wenn eine Seite mehrmals hintereinander die Mehrheit gewonnen hat, erkennt der Spieler, dass die andere Seite in der nächsten Runde eher die Mehrheit sein wird (richtig?) Und dies beeinflusst seine Stimme. Er strebt die Minderheit an, denn wenn er es einmal in die Minderheit schafft, schafft er es wahrscheinlich mehrmals dorthin (oder?) Und bekommt viele Punkte.

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  

Verwendungszweck

Für die erste Runde:

python gambler.py

und danach:

python gambler.py 101,100,001 etc.
Kommando
quelle
4
Mir gefällt, wie sicher Sie bei Ihrem Code zu sein scheinen, oder? : P
IEatBagels
7

Zellularer Automat

Hierbei werden herkömmliche Regeln für Conways Spiel des Lebens verwendet, um eine Seite auszuwählen. Zunächst wird aus den vorherigen Abstimmungen ein 2D-Raster erstellt. Dann wird die "Welt" um eine Stufe vorgerückt und die Gesamtzahl der verbleibenden lebenden Zellen berechnet. Ist diese Anzahl größer als die Hälfte der Gesamtzahl der Zellen, wird "gut" gewählt. Ansonsten wird "böse" gewählt.

Bitte verzeihen Sie alle Fehler, dies wurde während meiner Mittagspause zerschlagen. ;)

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;
    }
}
Graphentheorie
quelle
1
Ich habe die Druckzeile zum Testen aus dem Code entfernt. Java-Einträge müssen nur gut oder böse zurückgeben, nicht drucken.
Rainbolt
7

Der Ridge Professor

Ich hoffe, die Verwendung von Bibliotheken ist erlaubt. Ich habe keine Lust, dies ohne eine zu tun =)

Die Grundidee ist, für jeden Teilnehmer in den letzten Runden einen Grat-Regressionsklassifikator zu trainieren, wobei die 30 Ergebnisse vor jeder Runde als Merkmale verwendet werden. Ursprünglich beinhaltete es die letzte Runde der Ergebnisse, in der alle Spieler das Ergebnis für jeden Spieler vorhersagten, aber das verkürzte es ziemlich zeitnah, wenn die Anzahl der Teilnehmer größer wurde (etwa 50).

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

Kompilieren

Speichern Sie den Quellcode in einer Datei namens ridge_professor.cc , laden Sie die Eigen- Bibliothek herunter und entpacken Sie den darin enthaltenen Eigen-Ordner in denselben Ordner wie die Quelldatei. Kompilieren mit g++ -I. -O3 -ffast-math -o ridge_professor ridge_professor.cc.

Zu rennen

Rufen Sie ridge_professor.exe auf und geben Sie das gewünschte Argument an.

Frage

Da ich noch nirgendwo einen Kommentar abgeben kann, frage ich hier: Ist es aufgrund der Größenbeschränkung der Argumente unter Windows nicht unmöglich, die resultierenden Binärdateien mit dem gesamten Verlauf nach einigen hundert Umdrehungen aufzurufen? Ich dachte, Sie können nicht mehr als ~ 9000 Zeichen im Argument haben ...

dgel
quelle
Vielen Dank, dass Sie mich darauf aufmerksam gemacht haben . Ich werde einen Weg finden, um es zum Laufen zu bringen, wenn es in Java noch nicht funktioniert. Wenn Java das nicht kann, sagt mir die Forschung, dass C ++ dies kann, und ich werde die Gelegenheit nutzen, um C ++ neu zu lernen. Ich werde in Kürze mit Testergebnissen zurück sein.
Rainbolt
Wie sich herausstellt, unterliegt Java nicht den Einschränkungen der Eingabeaufforderung. Es scheint, dass nur Befehle, die größer als 32 KB sind, ein Problem verursachen. Hier ist mein Beweis (ich habe ihn selbst geschrieben): docs.google.com/document/d/… . Ich weiß es wirklich zu schätzen, dass Sie dies vor Beginn der morgigen Gerichtsverhandlungen ansprechen.
Rainbolt
@Rusher Es gibt bereits 57 Bots und Sie planen, dass jeder Lauf aus 1000 Runden besteht. Das würde Ihre Zeichenfolge zu 57.000 Zeichen (also> 32.000 Zeichen) machen, nicht wahr?
Plannapus
1
@Rusher Ich denke, es ist besser, die Zeitleiste um eine weitere Woche zu verlängern und die Teilnehmer zu bitten, ihre Programme so zu ändern, dass sie stdin lesen, anstatt eine Argumentzeichenfolge zu verwenden. Wäre für die meisten Programme trivial zu ändern
dgel
@dgel Die Zeitspanne für die Herausforderung ist unendlich lang, aber ich möchte die Regeln nicht so ändern, dass jeder seine Antwort neu schreiben muss. Ich bin mir ziemlich sicher, dass die Regel, die ich letzte Nacht hinzugefügt habe, nur einen einzigen Beitrag überflüssig macht, und ich plane, dieser Person zu helfen, falls sie jemals ihr Programm so weit bringt, dass es kompiliert wird.
Rainbolt
6

Crowley

Weil die Winchesters ohne diesen Kerl viel weniger interessant sind. Er steht offensichtlich auf der Seite des Bösen ... es sei denn, es wird benötigt, um sich um ein größeres Übel zu kümmern.

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

Ich schaue mir die letzten beiden Runden an (bisher 0 Kommas und 1 Komma) und wenn beide das Böse gewinnen lassen, stimme ich gut. Ansonsten stimme ich böse.

kaine
quelle
Verstehe ich das richtig? Du siehst auf die letzte Runde und wenn weniger als 50% der Stimmen "gut" sind, stehst du auf der Seite mit "gut", sonst mit dem Bösen? (Aus Neugier: Bevorzugen Sie kryptische Variablennamen oder ist es ein Unfall?)
Angelo Fuchs
1
@AngeloNeuschitzer Ich schaue mir die letzten beiden Runden an (bisher 0 Kommas und 1 Komma) und wenn beide das Böse gewinnen lassen, stimme ich gut. Ansonsten stimme ich böse. Ich bevorzuge Variablennamen, die kurz sind, wenn der Code kurz genug ist, wird der Zweck des Codes nicht verwechselt. Ich bin kein professioneller Programmierer und es war das erste Mal seit 6,5 Jahren, dass ich in Java programmiert habe oder etwas, für das jemand anderen den Code gesehen hat. Ich habe dies geschrieben, um mein Gedächtnis aufzufrischen. (TLDR ist für mich nicht kryptisch und ich bin der einzige, für den ich normalerweise
programmiere
Zur Klarheit ... Crowley hat als Mensch angefangen, also war es beabsichtigt, dass er gut anfängt ... Hatte nicht erwartet, dass er für alle Runden gut
bleibt