Good Versus Evil

112

Resultados - 19 de julho de 2014

O atual King of the Hill é Mercenary pelo usuário Fabigler ! Continue enviando entradas e derrubá-lo de seu trono!

Clique aqui para visualizar o placar.

Os programas enviados até 19 de julho de 2014 foram incluídos. Todos os outros envios serão incluídos em ensaios futuros. Novos resultados devem ser publicados por volta de 9 de agosto, para que você tenha bastante tempo.


Ilustração desenhada pelo irmão Ilustrado por Chris Rainbolt, meu irmão e recém-formado pela Savannah College of Art and Design

Introdução

Os anjos e demônios estão lutando e, como sempre, usando a terra como campo de batalha. Os seres humanos estão presos no meio e estão sendo forçados a tomar partido. Uma força neutra desconhecida recompensa aqueles que sempre lutam pelo lado perdedor.

O jogo

Em cada avaliação, você será emparelhado pseudo-aleatoriamente e depois embaralhado com 20 a 30 outras submissões. Cada julgamento será composto de 1000 rodadas. A cada rodada, você recebe uma entrada e espera-se que produza uma saída. Sua saída será gravada e pontuada. Este processo será repetido 1000 vezes.

Entrada

Você receberá um único argumento que representa os votos anteriores de cada jogador. As rodadas são delimitadas por vírgula. A 0representa um jogador que ficou do lado do mal naquela rodada. A 1representa um jogador que ficou do lado de Bom. Dentro de um teste, os jogadores sempre estarão na mesma ordem. Seu próprio voto será incluído, mas não explicitamente identificado. Por exemplo:

101.100.100

Neste exemplo, três rodadas foram concluídas e três jogadores estão competindo. Jogador um sempre do lado de Bom. Jogador dois sempre do lado do mal. O jogador três trocou de Bom na rodada 1 para Mal nas rodadas 2 e 3. Um desses jogadores era você.

Resultado

Submissões Java

  • Retorne a string goodse desejar ficar do lado de Good.
  • Retorne a corda evilse quiser ficar do lado do mal.

Envios não Java

  • Faça a saída da string goodpara stdout, se desejar ficar do lado de Bom.
  • Faça a saída da string evilpara stdout se você quiser ficar do lado do mal.

Se o seu programa gerar ou retornar qualquer outra coisa, lançar uma exceção, não compilar ou demorar mais de um segundo para produzir qualquer coisa nessa máquina exata , será desqualificado.

Pontuação

As pontuações serão postadas em uma planilha do Google Docs para facilitar a visualização assim que eu puder compilar todas as entradas atuais. Não se preocupe - eu continuarei executando testes enquanto vocês continuarem enviando programas!

  • Você recebe 3 pontos por tomar partido com a maioria durante uma rodada.
  • Você recebe n - 1 pontos por tomar partido da minoria durante uma rodada, em que n é o número de vezes consecutivas em que ficou do lado da minoria.

Sua pontuação será a mediana de 5 tentativas. Cada julgamento consiste em 1000 rodadas.

Entregas

Envios não Java

Você deve enviar um título exclusivo, um programa e uma linha de comando do Windows que executará seu programa. Lembre-se de que um argumento pode ser anexado a essa sequência. Por exemplo:

  • python Angel.py
    • Observe que este não possui argumentos. Esta é a primeira rodada! Esteja preparado para isso.
  • python Angel.py 11011,00101,11101,11111,00001,11001,11001

Submissões Java

Você deve enviar um título exclusivo e uma classe Java que estenda a classe Human abstrata, escrita abaixo.

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

Testando

Se você quiser testar seu próprio envio, siga as instruções aqui .

Notas Adicionais

Você pode enviar quantas submissões quiser. Os envios que parecem estar em conluio serão desqualificados. O autor deste desafio será o único juiz nesse assunto.

Uma nova instância do seu programa ou classe Java será criada toda vez que for solicitada. Você pode persistir nas informações gravando em um arquivo. Você não pode modificar a estrutura ou o comportamento de qualquer coisa, exceto da sua própria classe.

Os jogadores serão embaralhados antes do início do teste. Demon e Angel vão participar de todas as tentativas. Se o número de jogadores for par, Petyr Baelish também participará. Demônios lutam pelo mal, Angel for Good e Petyr Baelish escolhe um lado pseudo-aleatório.

Rainbolt
fonte
2
Os comentários foram eliminados, pois estavam obsoletos e a pedido do OP. Notifique-me sobre quaisquer comentários que precisem ser removidos.
Maçaneta
7
Woah, OP muda seu nome de usuário. Ok, então quando o resultado será exibido?
Just just
6
@Rainbolt Este deve ser um inferno de um trabalho, executando este desafio! O motivo dessa atenção é a simplicidade do protocolo e das regras, tornando-o acessível e, ao mesmo tempo, permitindo entradas simples e funcionais . TL; DR: Seu desafio é bom demais! : D
tomsmeding 19/07/2014
3
@dgel Vou postar os dados brutos, superior, inferior, médias e talvez um gráfico de linhas para que possamos ver quem se saiu melhor à medida que a competição se arrastava.
Rainbolt
6
Um dos pods terminou com 10 participações que votaram da mesma maneira todas as vezes. Conseqüentemente, dois usuários terminaram com pontuações perfeitas ou "uma volta abaixo da perfeição" de cerca de 450.000. As mesmas entradas foram pontuadas por volta de 1900 em outros ensaios. A pontuação média é próxima de 2000. Por causa do desequilíbrio extremo nos resultados, decidi que um número mais significativo seria uma mediana. Editei o desafio para que, após 5 tentativas, o vencedor fosse a finalização com a mediana mais alta. Se alguém achar que mudar de média para mediana é injusto ou uma má escolha, por favor, comente.
Rainbolt

Respostas:

11

O mercenário

Sempre fique do lado de quem pagou mais dinheiro na última rodada.

Levando em conta que pessoas boas ganham estatisticamente mais.

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
fonte
2
Este é o segundo post para dizer algo sobre dinheiro. Estou faltando uma referência ou algo assim?
21714 Rainbolt
É verdade, mas esse cara é um bastardo ainda mais maligno. Abandonando seus amigos a cada turno, apenas por uma questão de dinheiro.
Fabuller
Sua declaração de switch estava sem uma declaração de retorno para o caso padrão, fazendo com que não fosse compilado. Eu adicionei um aleatório.
Rainbolt
4
Parabéns, rei da colina! Não entendo como essa entrada vence. Gostaria de adicionar uma explicação, agora que ela possui uma recompensa de 300 reputação?
Rainbolt
4
Possivelmente um bug, ou eu não entendi os comentários e a descrição, mas o Mercenary não faz o que deveria. Exceto na primeira rodada aleatória, ele sempre estará do lado do mal, a menos que menos de 1/6 das pessoas tenham votado no mal na rodada anterior.
Jaybz 23/07/2014
39

Hipster, Rubi

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

Simplesmente combina com a minoria da última rodada, apenas porque todo o resto é mainstream.

Corra como

ruby hipster.rb
Martin Ender
fonte
30

Petyr Baelish

Você nunca sabe de que lado Petyr Baelish está.

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

Esta entrada será incluída apenas se o número de jogadores for par. Isso garante que sempre haverá uma maioria.

Rainbolt
fonte
28
Do lado de Petyr Baelish, obviamente.
Cthulhu
2
@ Kevin Ele sempre vence a maioria dos bots. Geralmente marca 27ish.
Cjfaure 9/07
3
@Kevin Esta entrada foi enviada pelo autor do desafio. Não foi feito para fazer bem. Existe para garantir que sempre haverá uma maioria, porque com um número par de jogadores, pode haver um empate.
Rainbolt
4
Por que, oh Deus, por que esse tem mais votos? Simplesmente não é justo .
tomsmeding
3
@tomsmeding Não. É uma citação de Game of Thrones lol.
Rainbolt
29

C ++, O Meta Cientista

Este faz essencialmente o mesmo que O Cientista, mas não opera nas rodadas como um todo, mas nos jogadores individuais. Ele tenta mapear uma onda (ou uma função constante) para cada jogador separadamente e prevê seu movimento na próxima rodada. A partir da previsão da rodada resultante, o Meta Scientist escolhe qualquer lado que pareça ter maioria.

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

Se você deseja ativar as instruções de depuração, altere a linha de leitura #if 0para #if 1.

Compile com g++ -O3 -std=c++0x -o MetaScientist MetaScientist.cpp(você não precisa de avisos, então não -Wall) e execute MetaScientist.exe(possivelmente incluindo o argumento, é claro). Se você perguntar muito bem, posso fornecer um executável do Windows.

Edição: Aparentemente, a versão anterior ficou sem tempo em torno de 600 rodadas no jogo. Isso não deveria fazer isso. Seu consumo de tempo é controlado pela #define WINDOW (...)linha, mais é mais lento, mas olha mais para trás.

tomsmeding
fonte
2
Eu humildemente sugiro que você tente escolher o lado perdedor. Se você conseguir adivinhar corretamente, receberá mais de 3 pontos por rodada.
Kevin
11
@ Kevin Isso é verdade, mas achei que poderia adivinhar o lado errado muito rapidamente, e você precisa adivinhar corretamente o lado perdedor mais de sete vezes seguidas para obter uma melhoria em relação a sempre acertar a maioria. Eu posso mudar isso embora.
tomsmeding
11
@ Kevin Além disso, eu gostaria de ver primeiro como essas coisas (cientista e meta-cientista) quando Rusher recebe um placar para nós neste fim de semana, como indicou nos comentários ao OP. Rusher, desculpe, mas eu sou muito preguiçoso para compilar todas as coisas me ... :)
tomsmeding
3
Não se preocupe! Provavelmente não é seguro executá-las de qualquer maneira. Apenas deixe-me estragar minha máquina com um código escrito por 50 estranhos na Internet.
Rainbolt
11
@ Kevin Mas isso é tão MUITO ! Eu posso, de fato, mas não gosto. Vou ver como essas tarifas.
tomsmeding
26

Anjo

O jogador mais puro de todos.

Programa

print "good"

Comando

python Angel.py
Rainbolt
fonte
22
Python é uma boa linguagem. Parece natural que o anjo o use.
jpmc26
23
Gostaria de lembrar às pessoas que um Python é uma cobra. Uma serpente.
Lister
3
@ MrLister Gostaria de lembrá-lo de que Lúcifer era um grande anjo antes que Deus o expulsasse do céu?
Zibbobz
11
@ Zibbobz Sim ... pena mesmo, que eles tenham caído. Eles poderiam ter conseguido tanto juntos.
Sr. 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";
           }
        }
    }
}

No livro 7, The Atlantis Complex , Artemis Fowl contraiu uma doença psicológica (chamada Atlantis complex) que o forçou a fazer tudo em múltiplos de 5 (fala, ações, etc.). Quando ele não conseguiu fazer isso em vários múltiplos de 5, ele entrou em pânico. Faço basicamente isso: veja se o bem ou o mal (viés intencional) é divisível por 5, se não é, então entro em pânico e vejo o que era maior e corro com isso ou entre em pânico ainda mais e escolho aleatoriamente.

Kyle Kanos
fonte
4
Quando li Artemis Fowl na escola secundária, apenas dois livros existiam. É bom ver que agora existem sete e que a Disney está entrando em um filme.
Rainbolt
11
Na verdade, existem 8 livros.
Kyle Kanos
7
Quanto mais, melhor (a menos que você está lendo The Wheel of Time)
Rainbolt
11
E você esqueceu break;no seu switch.
precisa saber é o seguinte
11
@ johnchen902, @ Manu: Não tenho muita experiência em java (eu uso o Fortran90 + e vejo apenas java aqui), daí os meus erros. Vou consertá-los quando chegar ao escritório em uma hora.
Kyle Kanos
19

Disparnumerofóbico

Números ímpares são aterradores.

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
fonte
17
O comentário me fez rir / bufar.
Phyrfox
17

Linus, Ruby

Procura confundir os analistas sempre quebrando o padrão .

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

Salvar como linus.rbe executar comruby linus.rb

histocrata
fonte
16

O BackPacker

Determina um jogador que ainda escolheu a minoria correspondente e escolhe seu último voto.

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

A multidão

Determina um jogador que escolheu a maioria correspondente ainda e escolhe seu último voto.

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
fonte
Programa muito limpo!
Rainbolt
Opa, acho que posso ter copiado seu programa em um idioma diferente.
PyRulez
@Rusher Atualizei o código e gostaria de adicioná-lo como duas entradas, uma com goWithMajority = truee outra onde está false. Está tudo bem ou preciso adicionar um segundo BackPacker para isso?
Angelo Fuchs
@AngeloNeuschitzer Eu editei este post. Dessa forma, não esquecerei de adicionar os dois envios. Sugiro que você mude o nome realmente não criativo que eu dei e talvez adicione uma descrição para ambos, se quiser.
Rainbolt
11
@Rainbolt Eu gosto mais do seu FrontPacker, na verdade. Lol'd.
tomsmeding 19/07/2014
15

Vidente

Isso ainda está em andamento. Ainda não testei. Eu só queria ver se o OP acha que infringe as regras ou não.

A idéia é simular a próxima rodada executando todos os outros participantes algumas vezes para obter uma probabilidade do resultado e agir em conformidade.

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
fonte
Se o seu bot executa todos os outros bots a cada turno antes de responder, não demorará mais de 1s para responder?
plannapus
@ plannapus Eu vou adivinhar a suposição com este bot é que todo mundo vai errar por precaução e evitar algo próximo a 1 segundo de espera. Acho que vale a pena enviar e entrar que consiste em uma espera de 0,9 segundo, antes de retornar "bom", apenas para mexer com ele. Na verdade, o SBoss me venceu: D
scragar
Yahhh! Então eu teria que colocar na lista negra esse bot no meu código. Isso seria frustrante ... Também com entradas diferentes em ambientes diferentes, como Python ou Perl, o carregamento repetido do intérprete pode ser suficiente para colocar esse código acima do limite de tempo.
217 Andris
16
Se alguém fizer a mesma coisa, você obtém um loop infinito.
Brilliand
4
O envio expirou. Anexei um perfilador e quase meio segundo é gasto chamando alguns envios. Pelo menos funciona, então parabéns por isso.
Rainbolt
15

C ++, o cientista

Este tenta, com o histórico do que a maioria escolheu por rodada wave( majority()dá a escolha da maioria em uma rodada), ajustar uma onda aos dados, de comprimento de onda 2*periode fase phase. Assim, dado 0,1,1,1,0,1,0,1,1,1,0,0,0,1,0que seleciona period=3, phase=5( maxat=={3,5}): suas pontuações se tornam 9 3 11 5 5 3 5 7 9 7 7 7 7 7 7. Ele faz um loop em todos os períodos possíveis e, se nesse período a pontuação for maior que no máximo atual, ele armazena o {period,phase}que ocorreu.

Em seguida, extrapola a onda encontrada para a próxima rodada e leva a maioria prevista.

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

Compile com g++ -O3 -std=c++0x -o Scientist Scientist.cpp(você não precisa de avisos, então não -Wall) e execute Scientist.exe(possivelmente incluindo o argumento, é claro). Se você perguntar muito bem, posso fornecer um executável do Windows.

Ah, e não ouse mexer com o formato de entrada. Caso contrário, fará coisas estranhas.

Edição: Aparentemente, a versão anterior ficou sem tempo em torno de 600 rodadas no jogo. Isso não deveria fazer isso. Seu consumo de tempo é controlado pela #define WINDOW (...)linha, mais é mais lento, mas olha mais para trás.

tomsmeding
fonte
8
Baixar executáveis ​​escritos por mais de sessenta estranhos na Internet parece uma má ideia.
Rainbolt
@Rusher Eu concordo totalmente. Se você deseja problemas, essa é a primeira etapa do guia "para manequins". A minha oferta permanece :) :)
tomsmeding
2
Consegui este para compilar (e competir) bem.
Rainbolt
14

Code Runner

Portanto, para tornar as coisas interessantes, criei um script para baixar automaticamente o código de todas as respostas postadas, compilá-lo, se necessário, e executar todas as soluções de acordo com as regras. Dessa forma, as pessoas podem verificar como estão se saindo. Apenas salve este script em run_all.py (requer BeautifulSoup) e depois:

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

Algumas coisas:

  1. Se você deseja adicionar suporte para mais idiomas ou remover o suporte para alguns, consulte def submission_type(lang).
  2. A extensão do script deve ser bastante fácil, mesmo para idiomas que exigem compilação (consulte CPPSubmission). O tipo de idioma é obtido da metatag tag < !-- language: lang-java -- >, portanto, adicione-o se desejar que seu código seja executado (remova os espaços extras antes e depois do <>). ATUALIZAÇÃO : Agora há alguma inferência extremamente básica para tentar detectar o idioma, se ele não estiver definido.
  3. Se seu código falhar na execução ou falha ao concluir dentro do prazo estipulado, ele será adicionado blacklist.texte removido automaticamente de futuras avaliações. Se você corrigir seu código, basta remover sua entrada da lista negra e executar novamente get,

Idiomas atualmente suportados:

 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
}

Sem mais delongas:

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
fonte
Por que nenhum idioma Fortran ??
Kyle Kanos
@KyleKanos - eu adicionei suporte para ele, atualizará o código em breve.
WhatAWorld
Yay! I (sorta) trabalhou duro em minha submissão Fortran & Rusher não pode fazê-lo funcionar, então eu gostaria de alguém para obtê-lo :)
Kyle Kanos
11
@Rusher: Eu concordo com PeterTaylor nesta: sintaxe destacada, pois a única edição sugerida deve ser rejeitada. As edições devem ser usadas para correções substanciais , não para pequenas coisas.
Kyle Kanos
11
Você merece o representante por isso, mas como essa não é exatamente uma resposta para a pergunta (e provavelmente poderia se beneficiar da comunidade adicionando coisas para outros idiomas), acho que esse tecnicamente deveria ser um wiki da comunidade.
Martin Ender
13

A Mente Bonita, Ruby

Toma sua decisão com base em padrões de significado questionável na representação de bits da última rodada

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

Corra como

ruby beautiful-mind.rb
Martin Ender
fonte
13

Piustitious, Lua

Um programa supersticioso que acredita em Sinais e Maravilhas.

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

execute-o com:

lua Piustitious.lua

seguido pela entrada.

AndoDaan
fonte
11

Os Winchesters

Sam e Dean são bons (na maioria das vezes).

package Humans;

public class TheWinchesters extends Human {

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

}
CommonGuy
fonte
Tem certeza de que 9:1é a proporção certa? Talvez devêssemos fazer uma mineração de dados e obter uma proporção mais precisa?
recursion.ninja
11
@awashburn eu comecei a assistir Supernatural 2 meses atrás (agora preso na estação 9) e 9:1parece ok para mim;)
CommonGuy
10

Estatístico

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";
    }
}
Não merecido
fonte
5
Essa segunda última linha é tão incrível
cjfaure
5
@ Indeservido Em vez de Math.ceil(Math.random()-Math.random())você também pode fazer exatamente Math.round(Math.random()).
tomsmeding
10

R, um bot um tanto bayesiano

Use a tabela de frequências para cada usuário como a probabilidade anterior de saída de outros usuários.

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

Chamado usando Rscript BayesianBot.Rseguido pela entrada.

Edit : Apenas para esclarecer o que isso está fazendo, aqui está um passo a passo com a entrada de exemplo:

> 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

Então a linha iniciada por result<-, para cada jogador, escolhe aleatoriamente 0 ou 1 usando esta última tabela como pesos (ou seja, para o jogador 1, a probabilidade de escolher 0 é 2/7, de escolher 1 5/7, etc.). Ele escolhe um resultado para cada jogador / coluna e finalmente retorna o número que terminou sendo o mais comum.

plannapus
fonte
10

suíço

Sempre sustenta a neutralidade. Condenado a nunca vencer.

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
fonte
Eu não escrevi isso!
Rainbolt
Essa é a ironia. A neutralidade nunca vence #
fabigler
2
@Rusher ah eu entendi agora: D
fabigler
11
Ele nem compila - falta um ponto e vírgula.
Pa Elo Ebermann
9

HAL 9000

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

Edit: talvez isso seja mais adequado para o HAL 9000, mas tenha cuidado! Isso é muito mau. Eu recomendo cdesvaziar o diretório antes de executá-lo.

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

Isso remove um arquivo cwdpara cada chamada!

Invocação não tão óbvia:

Em M $

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

D:>hal_9000.pl
evil

Em * 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
fonte
Você precisa fornecer um comando que possa ser usado para executar seu programa. Consulte a seção "Entregas" do desafio para obter mais informações.
Rainbolt
@Rusher Done;)
core1024
9

Vontade da maioria

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

Salve-o como WotM.py, execute como python3 WotM.pyseguido pela entrada.

Um programa simples, apenas para ver como será. Vai com o que a maioria disse da última vez, ou então aleatoriamente.

isaacg
fonte
Você precisa fornecer um comando que possa ser usado para executar seu programa. Consulte a seção "Entregas" do desafio para obter mais informações.
Rainbolt
Droga, isso faz da minha uma duplicata. : D Mudei para minoria.
Martin Ender
@Rusher Adicionado o comando. É o que você estava procurando?
Isaacg
@isaacg Perfect!
Rainbolt
11
Eu calculei a classificação média das pontuações no placar, e essa entrada vence por essa medida.
Brilliand
9

Alan Shearer

Repete o que a pessoa que ele está sentado ao lado acabou de dizer. Se a pessoa estiver errada, ela passa para a próxima pessoa e repete o que ela diz.

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
fonte
Você faz referência a uma variável chamada lastRoundantes mesmo de declará-la. Além disso, você adicionou parênteses a todos, String.lengthmas não é uma função. Você pode levar sua submissão a um ponto em que ela será compilada?
Rainbolt
@Rusher - done :)
Algy Taylor
@ Algy: lastRound.lengthainda é acessado (no primeiro se) antes lastRoundé declarado (nesse caso, se é o resto). Tente compilar (e talvez executar) seu código antes de enviá-lo aqui.
Pa Elo Ebermann
@ PaŭloEbermann - desculpas, eu não estou em um ambiente onde eu possa executá-lo - alteração feita, embora
Algy Taylor
Agora você está fazendo referência a uma variável chamada "personToCopy" quando está fora do escopo. Acabei de movê-lo para dentro do bloco else para compilar, mas não sei se é isso que você queria.
21414 Rainbolt
8

Mais tarde é o mal, JavaScript ( node.js )

Mede a quantidade de tempo entre as execuções. Se a diferença de horário for maior que da última vez, deve ser ruim. Caso contrário, bom.

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

Correr com: node laterisevil.js

nderscore
fonte
8

Localizador de padrões, Python

Procura um padrão recorrente e, se não conseguir encontrar, apenas acompanha a maioria.

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

correr com

python3 pattern_finder.py
CesiumLifeJacket
fonte
11
Eu amo muito esse código, quando o executo, ele sempre recebe 3000 pts, de alguma forma.
Realdeo 10/07/2014
8

The Turncoat

O Turncoat acredita que, por causa dos outros combatentes até agora, a maioria alternará após cada rodada entre o bem e o mal com mais frequência do que permanece do mesmo lado. Assim, ele começa a primeira rodada arbitrariamente ao lado do bem e depois alterna cada rodada na tentativa de permanecer no time vencedor ou perdedor com mais frequência do que nunca.

package Humans;

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

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

Depois de escrever isso, percebi que, devido às entradas baseadas na análise estatística, o momento faria com que a maioria mudasse de lado menos à medida que mais rodadas fossem concluídas. Portanto, o Turncoat Lazy.

O Turncoat preguiçoso

O Lazy Turncoat começa como o Turncoat, mas, à medida que as rondas passam, ele fica mais preguiçoso e mais preguiçoso para mudar para o outro lado.

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
fonte
2
O Turncoat preguiçoso é ótimo!
Angelo Fuchs
Estou incluindo os dois se você não se importa.
Rainbolt
Continue. Estou curioso para ver como os dois se sairão, principalmente os que compilam estatísticas de votação.
Jaybz
@Rainbolt Acabei de notar um bug estúpido com o Turncoat. Não há necessidade de corrigi-lo embora. Ele ainda funciona, mas não totalmente como pretendido, e mesmo que não seja tarde demais para corrigi-lo, corrigi-lo fará com que ele se comporte exatamente como uma das entradas mais recentes. Sinta-se livre para incluir / excluir, se quiser.
Jaybz
8

Biógrafo, 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]

Minha tentativa de uma entrada quase inteligente (realmente inteligente exigiria testes em campo). Escrito em Ruby, há uma chance de que isso seja muito lento, mas de qualquer maneira na minha máquina leva 0,11 segundo para calcular a última rodada quando houver 40 jogadores aleatórios, então espero que funcione bem o suficiente.

salvar como biographer.rb, executar comoruby biographer.rb

A idéia é que, para cada jogador, ele calcule suas chances de escolher "bom", analisando suas próprias escolhas nas últimas dez rodadas e os resultados gerais, além de encontrar ocorrências no passado em que circunstâncias idênticas (seus votos + total) resultados). Ele escolhe o comprimento mais longo, até 10 rodadas, de forma que exista qualquer precedente, e usa isso para criar uma frequência (ajustada de acordo com a Lei de Sucessão de Laplace, para que nunca tenhamos 100% de confiança em ninguém).

Em seguida, ele executa algumas simulações e vê com que frequência o Good vence. Se as simulações ocorrerem da mesma maneira, provavelmente será uma boa previsão em geral, por isso escolhe a minoria prevista. Se não estiver confiante, escolhe a maioria prevista.

histocrata
fonte
8

Judas

Judas é uma pessoa muito boa. É uma pena que ele trai os mocinhos por alguns centavos.

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
fonte
11
Isso só nunca vota mal se não houver número suficiente de participantes, você pode querer remover o ,fora history, ainda mais, de modo Rusher vai dividir o jogo em grupos.
Angelo Fuchs
Eu não sabia que ele iria dividir o jogo em grupos. Na verdade, eu esperei que essa pergunta tivesse envios suficientes antes de postar minha resposta por causa do tamanho da string. Obrigado por me avisar.
William Barbosa
Se você souber como passar um argumento de 60000 caracteres para um processo no Windows, informe-me. Caso contrário, desculpe por estragar sua entrada e obrigado por corrigi-la! Eu não esperava receber tantos envios.
Rainbolt 14/07/2014
7

O jogador falacioso (Python)

Se um lado ganhou a maioria várias vezes seguidas, o jogador percebe que é mais provável que o outro lado seja a maioria na próxima rodada (certo?) E isso influencia seu voto. Ele aponta para a minoria, porque se ele chegar à minoria uma vez que provavelmente chegará lá várias vezes (certo?) E conseguirá muitos pontos.

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  

Uso

Para a primeira rodada:

python gambler.py

e depois:

python gambler.py 101,100,001 etc.
comando
fonte
4
Eu gosto de como você parece certo sobre o seu código, certo? : P
IEatBagels
7

Autômato Celular

Isso usa regras convencionais para o Jogo da Vida de Conway escolher um lado. Primeiro, uma grade 2D é criada a partir dos votos anteriores. Então, o "mundo" é avançado um estágio, e o número total de células vivas restantes é calculado. Se esse número for maior que a metade do número total de células, "bom" será escolhido. Caso contrário, o "mal" é escolhido.

Por favor, perdoe quaisquer erros, isso foi esmagado durante a minha hora de almoço. ;)

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;
    }
}
Teoria dos grafos
fonte
11
Eu removi a linha de impressão do código para teste. As entradas Java precisam apenas retornar o bem ou o mal, não imprimi-lo.
21714 Rainbolt
7

The Ridge Professor

Espero que o uso de bibliotecas seja permitido, não tenho vontade de fazer isso sem um =)

A idéia básica é treinar um classificador de regressão de crista para cada participante nas últimas rodadas, usando os 30 resultados antes de cada rodada como recursos. Originalmente, incluía a última rodada de resultados para todos os jogadores para prever o resultado de cada jogador, mas isso diminuía bastante o tempo quando o número de participantes fica maior (digamos, 50 ou mais).

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

Compilar

Salve o código-fonte em um arquivo chamado ridge_professor.cc, baixe a biblioteca Eigen e descompacte a pasta Eigen encontrada dentro da mesma pasta que o arquivo de origem. Compile com g++ -I. -O3 -ffast-math -o ridge_professor ridge_professor.cc.

Para correr

chame ridge_professor.exe e forneça o argumento conforme necessário.

Pergunta, questão

Como ainda não posso comentar em lugar algum, perguntarei aqui: o limite de tamanho do argumento no Windows não torna impossível chamar os binários resultantes com todo o histórico em algumas centenas de voltas? Eu pensei que você não pode ter mais do que ~ 9000 caracteres no argumento ...

dgel
fonte
Obrigado por chamar minha atenção para isso . Vou descobrir uma maneira de fazê-lo funcionar, se ainda não funcionar bem em Java. Se o Java não puder, as pesquisas me dizem que o C ++ pode, e aproveitarei a oportunidade para reaprender o C ++. Volto em breve com os resultados dos testes.
Rainbolt
Como se vê, Java não está sujeito às limitações do prompt de comando. Parece que apenas comandos maiores que 32k causam um problema. Aqui está minha prova (eu mesmo a escrevi): docs.google.com/document/d/… . Mais uma vez, eu realmente aprecio que você traga isso à tona antes que os testes comecem amanhã.
Rainbolt
@Rusher Já existem 57 bots e você planeja que cada corrida seja composta por 1000 rodadas. Isso faria sua string 57k caracteres (portanto> 32k), não seria?
plannapus
11
@Rusher Eu acho que pode ser melhor estender a linha do tempo por mais uma semana e pedir aos participantes que mudem seus programas para ler stdin em vez de usar uma sequência de argumentos. Seria trivial para a maioria dos programas mudarem
dgel 13/07/2014
@dgel A linha do tempo do desafio é infinitamente longa, mas não quero alterar as regras de maneira que todos tenham que reescrever sua resposta. Tenho certeza de que a regra que eu adicionei ontem à noite só estraga um único envio, e pretendo ajudar essa pessoa se ele conseguir que seu programa chegue a um ponto em que ele seja compilado.
Rainbolt
6

Crowley

Porque os Winchesters são muito menos interessantes sem esse sujeito. Ele obviamente apoia o mal ... a menos que seja necessário cuidar de um mal maior.

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

Olho para as duas últimas voltas (0 vírgulas até agora e 1 vírgula até agora) e, se as duas deixarem o mal vencer, eu voto no bem. Caso contrário, eu voto no mal.

Kaine
fonte
Eu entendi direito? Você olha para o último turno e se menos de 50% são "bons" vota do lado "bom" ou mal? (A título de curiosidade: Você prefere nomes de variáveis crípticos ou é um acidente?)
Angelo Fuchs
11
@AngeloNeuschitzer Olho para as duas últimas voltas (0 vírgulas até agora e 1 vírgula até agora) e, se as duas deixarem o mal vencer, voto bem. Caso contrário, eu voto no mal. Prefiro nomes de variáveis ​​que sejam curtos para digitar se o código for suficientemente curto para que o objetivo do código não seja confundido. Eu não sou um programador profissional e essa foi a primeira vez que programarei em java ou algo que alguém viu o código em 6,5 anos. Eu escrevi isso para refrescar minha memória. (TLDR eles não são enigmáticas para mim e eu sou o único que eu normalmente código para.)
kaine
Para maior clareza ... Crowley começou como um ser humano, por isso foi intencional, ele começa bem ... Não esperava que ele ficasse bom para todas as rodadas embora ... maldita
kaine