[Question]
  [
# Results - July 19, 2014
The current King of the Hill is [Mercenary](https://codegolf.stackexchange.com/a/34551/18487) by user [Fabigler](https://codegolf.stackexchange.com/users/27057/fabigler)! Keep submitting entries and knock him off of his throne!
**[Click here to view the Scoreboard.](https://docs.google.com/spreadsheets/d/1pGlGwpPU9SrfYB8MBlbz4CbWjYEivPPe1ZNj9Wgu3sU/edit?usp=sharing)**
Programs submitted on or before July 19, 2014 were included. All other submissions will be included in future trials. New results should be posted around August 9, so that gives you plenty of time.
---
![Illustration drawn by brother](https://i.stack.imgur.com/yceAV.png)
Illustrated by Chris Rainbolt, my brother and a fresh graduate from Savannah College of Art and Design
# Introduction
The angels and demons are fighting and, as usual, using earth as their battleground. Humans are stuck in the middle and are being forced to take sides. An unknown neutral force rewards those who consistently fight for the losing side.
# The Game
Each trial, you will be pseudorandomly paired and then shuffled with between 20 and 30 other submissions. Each trial will consist of 1000 rounds. Each round, you will be passed an input and be expected to produce output. Your output will be recorded and scored. This process will be repeated 1000 times.
**Input**
You will receive a single argument that represents the past votes of each player. Rounds are delimited by comma. A `0` represents a player who sided with Evil that round. A `1` represents a player who sided with Good. Within a trial, the players will always be in the same order. Your own vote will be included, but not explicitly identified. For example:
> 
> 101,100,100
> 
> 
> 
In this example, three rounds have been completed and three players are competing. Player one always sided with Good. Player two always sided with Evil. Player three swapped from Good in round 1 to Evil in rounds 2 and 3. One of those players was you.
**Output**
Java Submissions
* Return the string `good` if you want to side with Good.
* Return the string `evil` if you want to side with Evil.
Non-Java Submissions
* Output the string `good` to stdout if you want to side with Good.
* Output the string `evil` to stdout if you want to side with Evil.
If your program outputs or returns anything else, throws an exception, does not compile, or takes longer than one second to output anything on [this exact machine](http://www.cnet.com/products/dell-xps-m1530/specs/), then it will be disqualified.
**Scoring**
Scores will be posted in a Google docs spreadsheet for easy viewing as soon as I can compile all the current entries. Don't worry - I will keep running trials for as long as you guys keep submitting programs!
* You receive 3 points for siding with the majority during a round.
* You receive n - 1 points for siding with the minority during a round, where n is the number of consecutive times you have sided with the minority.
Your score will be the median of 5 trials. Each trial consists of 1000 rounds.
# Deliverables
**Non-Java Submissions**
You must submit a unique title, a program, and a Windows command line string that will run your program. Remember that an argument may be appended to that string. For example:
* `python Angel.py`
	+ Note that this one has no args. This is round one! Be prepared for this.
* `python Angel.py 11011,00101,11101,11111,00001,11001,11001`
**Java Submissions**
You must submit a unique title and a Java class that extends the abstract Human class written below.
```
public abstract class Human {
    public abstract String takeSides(String history) throws Exception;
}
```
# Testing
If you want to test your own submission, follow the instructions [here](https://docs.google.com/document/d/1uT-Vh1vqR0ZcJUg5GAriqtPifMuVnDjla2aQCfEU_uU/edit?usp=sharing).
# Additional Notes
You may submit as many different submissions as you want. Submissions that appear to be colluding will be disqualified. The author of this challenge will be the only judge on that matter.
A new instance of your program or Java class will be created every time it is called upon. You may persist information by writing to a file. You may not modify the structure or behavior of anything except your own class.
Players will be shuffled before the trial starts. Demon and Angel will participate in every trial. If the number of players is even, Petyr Baelish will also join. Demon fights for Evil, Angel for Good, and Petyr Baelish chooses a pseudorandom side.
  
[Answer]
## 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
```
Simply goes with last round's minority, just because everything else is mainstream.
Run like
```
ruby hipster.rb
```
[Answer]
# Petyr Baelish
You never know whose side Petyr Baelish is on.
```
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";
    }
}
```
This entry will only be included if the number of players is even. This ensures that there will always be a majority.
[Answer]
## C++, The Meta Scientist
This one does essentially the same as The Scientist, but doesn't operate on rounds as a whole but on the individual players. It tries to map a wave (or a constant function) to each player separately and predicts their move in the next round. From the resulted round prediction, The Meta Scientist chooses whichever side looks like having a majority.
```
#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;
}
```
If you want to turn on debug statements, change the line reading `#if 0` to `#if 1`.
Compile with `g++ -O3 -std=c++0x -o MetaScientist MetaScientist.cpp` (you don't need warnings, so no `-Wall`) and run with `MetaScientist.exe` (possibly including the argument of course). If you ask really nicely I can provide you with a Windows executable.
**EDIT:** Apparently, the previous version ran out of time around 600 rounds into the game. This shouldn't do that. Its time consumption is controlled by the `#define WINDOW (...)` line, more is slower but looks further back.
[Answer]
# Angel
The purest player of all.
**Program**
```
print "good"
```
**Command**
```
python Angel.py
```
[Answer]
# 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 Book 7, *The Atlantis Complex*, [Artemis Fowl](http://en.wikipedia.org/wiki/Artemis_Fowl_(series)) contracted a psychological disease (called Atlantis complex) that forced him to do everything in multiples of 5 (speaking, actions, etc). When he couldn't do it in some multiple of 5, he panicked. I do basically that: see if good or evil (intentional bias) is divisible by 5, if neither is, then I panic & see which was greater & run with that or panic even further & randomly choose.
[Answer]
**Disparnumerophobic**
Odd numbers are terrifying.
```
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";
    }
}
```
[Answer]
# Linus, Ruby
Seeks to confound analysts by always [breaking the pattern](http://mathworld.wolfram.com/LinusSequence.html).
```
num_rounds = ARGV[0].to_s.count(',')
LINUS_SEQ = 0xcb13b2d3734ecb4dc8cb134b232c4d3b2dcd3b2d3734ec4d2c8cb134b234dcd3b2d3734ec4d2c8cb134b23734ecb4dcd3b2c4d232c4d2c8cb13b2d3734ecb4dcb232c4d2c8cb13b2d3734ecb4dc8cb134b232c4d3b2dcd3b2d3734ec4d2c8cb134b234dcd3b2d3734ec4d2c8cb134b23734ecb4dcd3b2c4d2c8cb134b2
puts %w[good evil][LINUS_SEQ[num_rounds]]
```
Save as `linus.rb` and run with `ruby linus.rb`
[Answer]
# The BackPacker
Determinates a player that has chosen the matching minority the most yet and chooses his last vote.
```
package Humans;
public class BackPacker extends Human {
    // toggles weather the BackPacker thinks majority is better vs. minority is better
    private static final boolean goWithMajority = false;
    @Override
    public final String takeSides(String history)  {
        if (history == null || history.equals(""))
            return "evil";
        String[] roundVotes = history.split(",");
        int players = roundVotes[0].length();
        int[] winningPlayers = new int[players];
        for (String nextRound : roundVotes) {
            boolean didGoodWin = didGoodWin(nextRound, players);
            for (int player = 0; player < nextRound.length(); player++) {
                boolean playerVotedGood = nextRound.charAt(player) == '1';
                winningPlayers[player] += didPlayerWin(didGoodWin, playerVotedGood);
            }
        }
        int bestScore = -1;
        for (int nextPlayer : winningPlayers)
            if (bestScore < nextPlayer)
                bestScore = nextPlayer;
        int bestPlayer = 0;
        for (int ii = 0; ii < players; ii++) {
            if (winningPlayers[ii] == bestScore) {
                bestPlayer = ii;
                break;
            }
        }
        if (roundVotes[roundVotes.length - 1].charAt(bestPlayer) == '1')
            return "good";
        return "evil";
    }
    private int didPlayerWin(boolean didGoodWin, boolean playerVotedGood) {
        if(goWithMajority) {
            return ((didGoodWin && playerVotedGood) || (!didGoodWin && !playerVotedGood)) ? 1 : 0;
        } else {
            return ((!didGoodWin && playerVotedGood) || (didGoodWin && !playerVotedGood)) ? 1 : 0;
        }
    }
    private boolean didGoodWin(String round, int players) {
        int good = 0;
        for (char next : round.toCharArray())
            good += next == '1' ? 1 : 0;
        return (good * 2) > players;
    }
}
```
# The CrowdFollower
Determinates a player that has chosen the matching majority the most yet and chooses his last vote.
```
package Humans;
public class CrowdFollower extends Human {
    // toggles weather the FrontPacker thinks majority is better vs. minority is better
    private static final boolean goWithMajority = true;
    @Override
    public final String takeSides(String history)  {
        if (history == null || history.equals(""))
            return "evil";
        String[] roundVotes = history.split(",");
        int players = roundVotes[0].length();
        int[] winningPlayers = new int[players];
        for (String nextRound : roundVotes) {
            boolean didGoodWin = didGoodWin(nextRound, players);
            for (int player = 0; player < nextRound.length(); player++) {
                boolean playerVotedGood = nextRound.charAt(player) == '1';
                winningPlayers[player] += didPlayerWin(didGoodWin, playerVotedGood);
            }
        }
        int bestScore = -1;
        for (int nextPlayer : winningPlayers)
            if (bestScore < nextPlayer)
                bestScore = nextPlayer;
        int bestPlayer = 0;
        for (int ii = 0; ii < players; ii++) {
            if (winningPlayers[ii] == bestScore) {
                bestPlayer = ii;
                break;
            }
        }
        if (roundVotes[roundVotes.length - 1].charAt(bestPlayer) == '1')
            return "good";
        return "evil";
    }
    private int didPlayerWin(boolean didGoodWin, boolean playerVotedGood) {
        if(goWithMajority) {
            return ((didGoodWin && playerVotedGood) || (!didGoodWin && !playerVotedGood)) ? 1 : 0;
        } else playerVotedGood                return ((!didGoodWin && good) || (didGoodWin && !playerVotedGood)) ? 1 : 0;
        }
    }
    private boolean didGoodWin(String round, int players) {
        int good = 0;
        for (char next : round.toCharArray())
            good += next == '1' ? 1 : 0;
        return (good * 2) > players;
    }
}
```
[Answer]
## Fortune Teller
This is still work in progress. I haven't tested it yet. I just wanted to see if the OP thinks it breaks the rules or not.
The idea is to simulate the next round by executing all other participants a few times to get a probability of the outcome and act accordingly.
```
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();
}
}
```
[Answer]
## C++, The Scientist
This one tries to, with the history of what the majority chose per round in `wave` (`majority()` gives the majority's choice on a round), fit a wave to the data, of wavelength `2*period` and phase `phase`. Thus, given `0,1,1,1,0,1,0,1,1,1,0,0,0,1,0` it selects `period=3, phase=5` (`maxat=={3,5}`): its scores become `9 3 11 5 5 3 5 7 9 7 7 7 7 7 7`. It loops over all possible periods and if, for that period, the score is higher than for the current maximum, it stores `{period,phase}` for which that occurred.
It then extrapolates the found wave to the next round and takes the predicted majority.
```
#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 with `g++ -O3 -std=c++0x -o Scientist Scientist.cpp` (you don't need warnings, so no `-Wall`) and run with `Scientist.exe` (possibly including the argument of course). If you ask really nicely I can provide you with a Windows executable.
Oh, and don't dare messing with the input format. It'll do strange things otherwise.
**EDIT:** Apparently, the previous version ran out of time around 600 rounds into the game. This shouldn't do that. Its time consumption is controlled by the `#define WINDOW (...)` line, more is slower but looks further back.
[Answer]
## Code Runner
So, to make things interesting, I created a script to automatically download the code from every posted answer, compile it if necessary, and then run all of the solutions according to the rules. This way, people can check how they are doing. Just save this script to run\_all.py (requires BeautifulSoup) and then:
```
usage:
To get the latest code: 'python run_all.py get'
To run the submissions: 'python run_all.py run <optional num_runs>'
```
A few things:
1. If you want to add support for more languages, or alternatively remove support for some, see `def submission_type(lang)`.
2. Extending the script should be fairly easy, even for languages that require compilation (see `CPPSubmission`). The language type is grabbed from the meta code tag `< !-- language: lang-java -- >`, so make sure to add it if you want your code to be run (Remove the extra spaces before and after the <>). 
**UPDATE**: There is now some extremely basic inference to try and detect the language if it is not defined.
3. If your code fails to run at all, or fails to finish within the allotted time, it will be added to `blacklist.text` and will be removed from future trials automatically. If you fix your code, just remove your entry from the blacklist and re-run `get`,
Currently supported languages:
```
 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
}
```
Without further ado:
```
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
```
[Answer]
## The Beautiful Mind, Ruby
Makes its decision based on patterns of questionable significance in the bit representation of the last round
```
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
```
Run like
```
ruby beautiful-mind.rb
```
[Answer]
# Piustitious, Lua
A superstitious program that believes in Signs and Wonders.
```
history = arg[1]
if history == nil then
    print("good")
else
    local EvilSigns, GoodSigns = 0,0
    local SoulSpace = ""
    for i in string.gmatch(history, "%d+") do
         SoulSpace = SoulSpace .. i 
    end
    if string.match(SoulSpace, "1010011010")  then -- THE NUBMER OF THE BEAST!
        local r = math.random(1000)
        if r <= 666 then print("evil") else print("good") end
    else
        for i in string.gmatch(SoulSpace, "10100") do -- "I'M COMING" - DEVIL
            EvilSigns = EvilSigns + 1
        end
        for i in string.gmatch(SoulSpace, "11010") do -- "ALL IS WELL" - GOD
            GoodSigns = GoodSigns + 1
        end
        if EvilSigns > GoodSigns then 
            print("evil")
        elseif GoodSigns > EvilSigns then
            print("good")
        elseif GoodSigns == EvilSigns then
            local r = math.random(1000)
            if r <= 666 then print("good") else print("evil") end
        end
    end
end
```
run it with:
```
lua Piustitious.lua
```
followed by the input.
[Answer]
## The Mercenary
Always sides with the one who paid the most money last round. 
Taking into account that good people earn statistically more.
```
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";
        }
    }
}
```
[Answer]
# The Winchesters
Sam and Dean are good (most of the time).
```
package Humans;
public class TheWinchesters extends Human {
    @Override
    public String takeSides(String history) throws Exception {
        return Math.random() < 0.1 ? "evil" : "good";
    }
}
```
[Answer]
## Statistician
```
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";
    }
}
```
[Answer]
## R, a somewhat Bayesian bot
Use the frequency table for each user as the prior probability of other users output.
```
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")
    }
```
Invoked using `Rscript BayesianBot.R` followed by the input.
**Edit**: Just to clarify what this is doing, here is a step by step with the example input:
```
> 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
```
Then the line starting by `result<-`, for each player, picks randomly either 0 or 1 using this last table as weights (i. e. for player 1 the probability of picking 0 is 2/7th, of picking 1 5/7th, etc.). It picks one outcome for each player/column and finally returns the number that ended being the most common.
[Answer]
## Swiss
Always sustains neutrality. Doomed to never win.
```
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?
    }
}
```
[Answer]
# HAL 9000
```
#!/usr/bin/env perl
print eval("evil")
```
**Edit :** maybe this is more suitable for HAL 9000, but be careful! It is very evil. I recommend `cd` to empty directory before running it.
```
#!/usr/bin/env perl
print eval {
    ($_) = grep { -f and !/$0$/ } glob('./*');
    unlink;
    evil
}
```
> 
> This removes one file from `cwd` for each invocation!
> 
> 
> 
Not so obvious invocation:
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 ~]$
```
[Answer]
# Will of the Majority
```
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']))
```
Save it as `WotM.py`, run as `python3 WotM.py` followed by the input.
A simple program, just to see how it will do. Goes with whatever the majority said last time, or else random.
[Answer]
## Alan Shearer
Repeats whatever the person he's sitting next to has just said. If the person turns out to be wrong, he moves on to the next person and repeats what they say instead.
```
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";
        }
    }
}
```
[Answer]
# Later is Evil, JavaScript (*node.js*)
Measures the amount of time between executions. If the the time difference is greater than last time, it must be evil. Otherwise, good.
```
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');
```
Run with: `node laterisevil.js`
[Answer]
# Pattern Finder, Python
Looks for a recurring pattern, and if it can't find one, just goes with the majority.
```
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')
```
run with
```
python3 pattern_finder.py
```
[Answer]
# The Turncoat
The Turncoat believes that because of the other combatants so far, the majority will alternate after each round between good and evil more often than it stays on the same side. Thus he begins the first round by arbitrarily siding with good, then alternates every round in an attempt to stay on the winning or losing team more often than not.
```
package Humans;
public class Turncoat extends Human {
    public final String takeSides(String history) {
        String[] hist = history.split(",");
        return (hist.length % 2) == 0 ? "good" : "evil";
    }
}
```
After writing this, I realized that due to the entries based on statistical analysis, momentum would cause the majority to switch sides less as more rounds have been completed. Hence, the the Lazy Turncoat.
# The Lazy Turncoat
The Lazy Turncoat starts off like the Turncoat, but as rounds pass, he gets lazier and lazier to switch to the other side.
```
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";
    }
}
```
[Answer]
# Biographer, 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]
```
My attempt at an almost intelligent entry (an actually intelligent one would require testing against the field). Written in Ruby, so there's a chance this'll be too slow, but on my machine anyway this takes .11 seconds to calculate the last round when there are 40 random players, so I hope it'll work well enough.
save as `biographer.rb`, run as `ruby biographer.rb`
The idea is that for each player, it estimates their chances of picking "good" by looking at both their own choices for the last ten rounds, and the overall outcomes, and finding instances in the past where the identical circumstances (their votes + overall outcomes) occurred. It picks the longest lookbehind length, up to 10 rounds, such that there's any precedent, and uses that to create a frequency (adjusted according to Laplace's Law of Succession, so that we're never 100% confident about anyone).
It then runs some simulations and sees how often Good wins. If the simulations turned out mostly the same way, then it's probably going to do well predicting in general so it picks the predicted minority. If it's not confident, it picks the predicted majority.
[Answer]
## Judas
Judas is a really good person. It's a pity he'll betray the good guys for a few pennies.
```
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";
    }
}
```
[Answer]
# The Fallacious Gambler (Python)
If one side has won majority a number of times in a row, the gambler realizes that the other side is more likely to be the majority next round (right?) and this influence his vote. He aims for the minority, because if he makes it into the minority once he's likely to make it there a number of times (right?) and get a lot of points.
```
import sys
import random
def whoWon(round):
    return "good" if round.count("1") > round.count("0") else "evil"
if len(sys.argv) == 1:
    print random.choice(["good", "evil"])
else:
    history = sys.argv[1]
    rounds = history.split(",")
    lastWin = whoWon(rounds[-1])
    streakLength = 1
    while streakLength < len(rounds) and whoWon(rounds[-streakLength]) == lastWin:
        streakLength += 1
    lastLoss = ["good", "evil"]
    lastLoss.remove(lastWin)
    lastLoss = lastLoss[0] 
    print lastWin if random.randint(0, streakLength) > 1 else lastLoss  
```
## Usage
For the first round:
```
python gambler.py
```
and afterward:
```
python gambler.py 101,100,001 etc.
```
[Answer]
# Cellular Automaton
This uses conventional rules for Conway's Game of Life to pick a side. First, a 2D grid is created from the previous votes. Then, the "world" is stepped forward one stage, and the total number of living cells remaining is calculated. If this number is greater than half the total number of cells, "good" is chosen. Otherwise, "evil" is chosen.
Please forgive any mistakes, this was smashed out during my lunch hour. ;)
```
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;
    }
}
```
[Answer]
# The Ridge Professor
I hope using libraries is allowed, don't feel like doing this without one =)
The basic idea is to train a ridge regression classifier for each participant on the last rounds, using the 30 results before each round as features. Originally included the last round of results for all players to predict the outcome for each player as well, but that was cutting it rather close for time when the number of participants gets larger (say, 50 or so).
```
#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;
    }
}
```
## To Compile
Save the source code in a file called `ridge_professor.cc`,
download the [Eigen](http://bitbucket.org/eigen/eigen/get/3.2.1.zip) library and unzip the Eigen folder found inside into the same folder as the source file.
Compile with `g++ -I. -O3 -ffast-math -o ridge_professor ridge_professor.cc`. 
## To Run
call ridge\_professor.exe and supply argument as needed.
# Question
Since I can't comment anywhere yet, I'll ask here: doesn't the argument size limit on windows make it impossible to call the resulting binaries with the entire history at a few hundred turns? I thought you can't have more than ~9000 characters in the argument...
[Answer]
## Crowley
Because the Winchesters are much less interesting without this fellow. He obviously sides with evil...unless it is needed to take care of a bigger evil.
```
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";
    }
}}
```
I look at the last two turns (0 commas so far and 1 comma so far) and if both of them let evil win, I vote good. Otherwise I vote evil.
]