81
\$\begingroup\$

Final results are here !

Introduction

In 2042, the world has become overpopulated. Globalization, overcrowding, new lifestyles and a global lack of hygiene has caused a new pandemic to spread. During those hard times, state leaders have to manage the situation. You can't let your population be decimated, but maybe you could benefit by letting your neighbors to die...

Glossary

Healthy: People not infected
Infected: People who can die from the pandemic
Dead: Body count, no particular effect (only scoring)
Infection Rate: Number of Healthy who will become Infected each turn
Contagion Rate: Percentage of Infected that will convert Healthy to Infected each turn
Lethality Rate: Percentage of Infected that will die each turn
Migration Rate: Percentage of both Healthy and Infected that will emigrate/immigrate each turn
Local: Affects only your state
Global: Affects every state

Principle

Each of the players will manage one town, starting with 100 people. Unfortunately, among them is one Infected.

The game is turn-based. A turn consists of seven phases, the last one being interactive (asking bots for a command). The order of the players is randomized each turn. The next phase begins when the previous phase has been executed by every town (Turn 1: Player 1, Player 2, Player 3... ; Turn 2: Player 3, Player 2, Player 1...) :

1. Mutation                                 - AUTOMATED
2. Reproduction                             - AUTOMATED
3. Migration                                - AUTOMATED
4. Infection                                - AUTOMATED
5. Contagion                                - AUTOMATED
6. Extinction                               - AUTOMATED
7. Players Turn                             - INTERACTIVE

The controller provides you with input via command arguments, and your program has to output via stdout.

Syntax

Input

Each time your program is called, it will receive arguments in this format:

Round;YourPlayerId;PlayerId_Healthy_Infected_Dead_InfectionRate_ContagionRate_LethalityRate_MigrationRate;PlayerId_Healthy_Infected_Dead_InfectionRate_ContagionRate_LethalityRate_MigrationRate;...

Round are 1-indexed.

Example input

6;2;1_106_23_9_2_4_13_5;0_20_53_62_16_20_35_5;2_20_53_62_16_20_35_5

Here, you see it is the 6th round and you are player 2. You have 20 healthy, 53 infected, 62 dead, 16% infection rate, 20% contagion rate, 35% lethality rate, and a 5% migration rate.

Output

You have to output three characters (no space, no separator), which each correspond to one action you'll take this turn. The order of the characters determine the order of the actions. You can output the same actions multiple times.

N: Do Nothing
M: Research Microbiology [Effects: Reduce local Infection Rate by 4%]
E: Research Epidemiology [Effects: Reduce local Contagion Rate by 8%]
I: Research Immunology [Effects: Reduce local Lethality Rate by 4%]
V: Research Vaccination [Effects: Reduce local Infection Rate by one, reduce local Contagion Rate by 4%, reduce local Lethality Rate by 2%]
C: Give Cure [Effects: Convert 10 local Infected to Healthy]
Q: Quarantine [Effects: Remove 30 local Infected]
O: Open Borders [Effects: Increase local Migration Rate by 10%]
B: Close Borders [Effects: Decrease local Migration Rate by 10%]
T: BioTerrorism [Effects: Convert 4 global Healthy to Infected]
W: Weaponization [Effects: Increase global Infection Rate by 1, increase global Lethality Rate by 2%]
D: Dissemination [Effects: Increase global Infection Rate by 1, increase global Contagion Rate by 2%]
P: Pacification [Effects: Decrease global Infection Rate by 1, decrease global Contagion Rate by 1%, decrease global Lethality Rate by 1%]

Gameplay

All phases

Invalid command = Nothing
Percentage are added up like integers, i.e. 10% - 4% = 6%. When percentage are applied in a formula, the result is floored.

Phase 1: Mutation

The pandemic is becoming more potent. Each turn, it randomly gains one of these attributes (this mutation affects all players at once):

  • Increase global Infection Rate by 2
  • Increase global Contagion Rate by 5%
  • Increase global Lethality Rate by 5%

Phase 2: Reproduction

Every five rounds (round 5, 10, 15...), new citizens will be born. Each pair of Healthy will make one Healthy (23 Healthy generate 11 new Healthy). Each pair of Infected will make one Infected.

Phase 3: Migration

Each turn, a percentage of Healthy and Infected will leave states, depending on their Migration Rate (10 Healthy will leave a state with 100 Healthy and 10% Migration Rate). Then, the migrants will be distributed among every state, once again depending on Migration Rate. (The rates of each state are weighted and migrants are then all distributed accordingly).

Phase 4: Infection

Healthy of each state are converted to Infected, according to Infection Rate.

Phase 5: Contagion

Healthy of each state are converted to Infected, according to Contagion Rate. The number is calculated by multiplying the Infected by the Contagion Rate.

Phase 6: Extinction

Infected are converted to Dead, according to Lethality Rate. The number is calculated by multiplying the Infected by the Lethality Rate.

Phase 7: Players turn

Each player receive input and must output three actions, that are executed in the order they are output.

Rules

  • Bots should not be written to beat or support specific other bots.
  • Writing to files is allowed. Please write to "yoursubmissionname.txt", the folder will be emptied before a game starts. Other external resources are disallowed.
  • Your submission has one second to respond (per town).
  • Provide commands to compile and run your submissions.

Winning

Winner is the one with the most Healthy after 50 rounds. If a player is the last alive (more than 0 Healthy or Infected) the game stops and he wins. If multiple players have the same amount of Healthy, the one with most Infected will win, then the one with fewer Deads.

Controller

You can find the controller on GitHub. It also contains three samplebots, written in Java.
To make it run, check out the project and open it in your Java IDE. The entry point in the main method of the class Game. Java 8 required.

To add bots, first you need either the compiled version for Java (.class files) or the sources for interpreted languages. Place them in the root folder of the project. Then, create a new Java class in the players package (you can take example on the already existing bots). This class must implement Player to override the method String getCmd(). The String returned is the shell command to run your bots. You can for example make a Ruby bot work with this command : return "C:\Ruby\bin\ruby.exe MyBot.rb";. Finally, add the bot in the players array at the top of the Game class.

Final Results (2016-03-04 08:22 GMT)

Global (100 reputation) :

100 games results : http://pasted.co/942200ff

1. EvilBot (24, 249, 436)
2. Triage (23, 538, 486)
3. WICKED (23, 537, 489)
4. Israel (23, 40, 240)
5. InfectedTown (22, 736, 482)
6. ZombieState (22, 229, 369)
7. Mooch (22, 87, 206)
8. InfectedHaven (21, 723, 483)
9. Crossroads (16, 9, 136)
10. TheKeeper (3, 4, 138)
11. Terrorist (0, 595, 496)
12. InfectionBot (0, 511, 430)
13. FamilyValues (0, 6, 291)
14. UndecidedBot (0, 0, 20)
15. XenoBot (0, 0, 26)
16. Researcher (0, 0, 33)
17. Strategist (0, 0, 42)
18. TheCure (0, 0, 55)
19. Socialist (0, 0, 67)
20. TrumpBot (0, 0, 77)
21. CullBot (0, 0, 81)
22. BackStabber (0, 0, 87)
23. BlunderBot (0, 0, 104)
24. RemoveInfected (0, 0, 111)
25. PFC (0, 0, 117)
26. BioterroristBot (0, 0, 118)
27. PassiveBot (0, 0, 118)
28. Smaug (0, 0, 118)
29. WeaponOfMassDissemination (0, 0, 119)
30. AllOrNothing (0, 0, 121)
31. Obamacare (0, 0, 122)
32. DisseminationBot (0, 0, 123)
33. CureThenQuarantine (0, 0, 125)
34. Madagascar (0, 0, 129)
35. OpenAndClose (0, 0, 129)
36. ThePacifist (0, 0, 130)
37. MedicBot (0, 0, 131)
38. Medic (0, 0, 133)
39. Salt (0, 0, 134)
40. Piecemeal (0, 0, 136)
41. Graymalkin (0, 0, 137)
42. PureBot (0, 0, 140)
43. MadScienceBot (0, 0, 144)
44. BipolarBot (0, 0, 149)
45. RedCross (0, 0, 151)

Doomsday-less (200 reputation) :

100 games results : http://pasted.co/220b575b

1. FamilyValues (5708, 14, 2)
2. BlunderBot (5614, 12, 3)
3. Graymalkin (5597, 17, 4)
4. PureBot (5550, 12, 5)
5. Crossroads (5543, 11, 4)
6. Salt (5488, 24, 7)
7. CureThenQuarantine (5453, 13, 7)
8. Piecemeal (5358, 121, 23)
9. TrumpBot (5355, 12, 5)
10. CullBot (5288, 12, 9)
11. AllOrNothing (5284, 13, 10)
12. Madagascar (5060, 180, 35)
13. TheKeeper (4934, 165, 44)
14. WICKED (4714, 25, 5)
15. Strategist (2266, 25, 5)
16. BackStabber (2180, 1327, 596)
17. RemoveInfected (2021, 33, 27)
18. OpenAndClose (1945, 667, 394)
19. Triage (1773, 401, 80)
20. TheCure (1465, 46, 26)
21. Obamacare (1263, 525, 247)
22. Mooch (1103, 546, 269)
23. Israel (1102, 580, 292)
24. RedCross (1086, 1700, 727)
25. ThePacifist (1069, 636, 580)
26. Researcher (1035, 113, 37)
27. UndecidedBot (825, 219, 93)
28. PassiveBot (510, 990, 567)
29. MedicBot (411, 1474, 667)
30. Medic (392, 1690, 619)
31. Socialist (139, 63, 90)
32. XenoBot (0, 82, 170)

Thank you everyone for your participation. I hope you had as great a time designing and coding your bots as I had running the game.

\$\endgroup\$
  • 9
    \$\begingroup\$ Can we get an Execute command that murders X amount of infected (turning them straight to dead)? Probably not a viable method to winning, but an action that seems legitimate. Unless that's what Quarantine does (it is unclear). \$\endgroup\$ – Draco18s no longer trusts SE Jan 25 '16 at 18:20
  • 3
    \$\begingroup\$ Quick grammar note: "Sane" means "mentally stable"; the word you're (probably) looking for here is "healthy." (Would I be correct in guessing that your first language is Spanish, where "sano" means "healthy," or something closely related?) \$\endgroup\$ – Mason Wheeler Jan 25 '16 at 20:18
  • 5
    \$\begingroup\$ @MasonWheeler Nitpicking terminology note: Your note was a terminology or vocabulary note as there was no grammar involved ;) \$\endgroup\$ – Jan Jan 25 '16 at 22:50
  • 3
    \$\begingroup\$ @Thrax The way turns are currently handled (randomized at the start, same order from then on), gives players who come later in the turn order a huge advantage, which makes the end result wildly variant. Perhaps if you either 1) randomized the turn order each round, or 2) make everyone view the same state during their turn and apply the changes to everyone simultaneously at the end of the round, then the results might be more balanced, and be based more on the quality of the submission. I tested the first option, and the results are much more consistent. \$\endgroup\$ – Mwr247 Jan 26 '16 at 6:13
  • 7
    \$\begingroup\$ @Thrax There's currently an overabundance of bots that exist simply to "destroy the world". While this can be a fun challenge, it's at the point where bots actually attempting to compete can't effectively counter it anymore, and we're left with whatever bots are programmed to "Cure X 3" at the end as the winners. I'd like to suggest a rule change where in order to be considered for the KOTH, bots need to at least be capable of ending up with positive "sanes" in a 1-on-1 match up against PassiveBot? The challenge is more fun when strategies actually have an effect. \$\endgroup\$ – Mwr247 Jan 26 '16 at 22:05

37 Answers 37

1
2
2
\$\begingroup\$

BlunderBot, Java

BlunderBot does its best to keep people healthy by reducing infection rate and curing. Thereafter, reduce contagion rate. If there are still turns, reduce lethality, then be a pacifist.

import java.util.ArrayList;
import java.util.List;

public class BlunderBot {

int round;
int phase;
int playerID;
int thisTownID;

List<State> states;
List<State> otherStates;

State thisState;
String action = "";
int cc=0; // command count

public static void main(String[] args){
    new BlunderBot().sleep(args[0].split(";"));
}

private void action(String newAction) {
    action += newAction;
    cc+= newAction.length();
    if (cc>=3) {
        System.out.println(action.substring(0, 3));
        System.exit(0);;
    }
}
private void sleep(String[] args) {
    
    round = Integer.parseInt(args[0]);
    thisTownID = Integer.parseInt(args[1]);
    
    states = new ArrayList<>();
    otherStates = new ArrayList<>();
    
    for (int i = 2; i < args.length; i++){
        states.add(new State(args[i]));
    }

    for (State state : states){
        if (state.isMine()) {
            thisState = state;
        } else {
            otherStates.add(state);
        }
    }

    // Round specific commands
    if (round == 1)                                 { action("B");   }
    if (round == 50)                                { action("CCC"); }

    for (int i=0;i<3;i++){
      if (thisState.getInfectionRate() >= 4)    { action("M"); thisState.infectionRate -= 4;}
    }
    
    if (thisState.getInfected() >= 5)   {
        if (thisState.getInfected() < 15)           { action("C");   }
        else if (thisState.getInfected() < 25)      { action("CC");  }
        else if (thisState.getInfected() < 35)      { action("CCC"); }
        else if (thisState.getInfected() < 45)      { action("QC");  }
        else if (thisState.getInfected() < 55)      { action("QCC"); }
        else if (thisState.getInfected() < 65)      { action("QQ");  }
        else if (thisState.getInfected() < 75)      { action("QQC"); }
        else if (thisState.getInfected() < 85)      { action("QQC"); }
        else                                        { action("QQQ"); }
    }
    
    for (int i=0;i<3;i++){
        if (thisState.getContagionRate() >= 8)      { action("E"); thisState.contagionRate -= 8;}
    }
    
    for (int i=0;i<3;i++){
        if (thisState.getLethalityRate() >= 4)      { action("I"); thisState.lethalityRate -= 4;}
    }
    
    // Nothing else to do
    action("PPP");

}


private class State {
     
    private final int ownerId;
    private int healthy;
    private int infected;
    private int dead;
    private int infectionRate;
    private int contagionRate;
    private int lethalityRate;
    private int migrationRate;

    public State(String string) {
        String[] args = string.split("_");
        ownerId = Integer.parseInt(args[0]);
        healthy = Integer.parseInt(args[1]);
        infected = Integer.parseInt(args[2]);
        dead = Integer.parseInt(args[3]);
        infectionRate = Integer.parseInt(args[4]);
        contagionRate = Integer.parseInt(args[5]);
        lethalityRate = Integer.parseInt(args[6]);
        migrationRate = Integer.parseInt(args[7]);
    }
    
    public int getOwnerId() {
        return ownerId;
    }

    public int getHealthy() {
        return healthy;
    }

    public int getInfected() {
        return infected;
    }

    public int getDead() {
        return dead;
    }

    public int getInfectionRate() {
        return infectionRate;
    }

    public int getContagionRate() {
        return contagionRate;
    }

    public int getLethalityRate() {
        return lethalityRate;
    }

    public int getMigrationRate() {
        return migrationRate;
    }

    public boolean isMine(){
        return getOwnerId() == thisTownID;
    }

}

}

Local results after 10 games (50 rounds) with Java bots:

################################
1. BlunderBot (679, 0, 267)
2. CureThenQuarantine (407, 0, 277)
3. Graymalkin (302, 0, 217)
4. InfectedTown (30, 2298, 436)
5. Triage (30, 1095, 579)
6. ZombieState (30, 1043, 590)
7. EvilBot (30, 549, 540)
8. Mooch (30, 434, 327)
9. Madagascar (1, 0, 152)
10. BipolarBot (1, 0, 223)
11. InfectionBot (0, 1049, 542)
12. MedicBot (0, 1, 156)
13. Researcher (0, 0, 72)
14. TheCure (0, 0, 89)
15. PassiveBot (0, 0, 134)
16. WeaponOfMassDissemination (0, 0, 135)
17. BioterroristBot (0, 0, 135)
18. TrumpBot (0, 0, 234)
| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

UndecidedBot, Python

This bot can't decide what the best strategy is, so he's trying to mix three of them.

  1. Quarantine. Seems to be pretty effective at removing infected people, who we don't want around.
  2. Science. One of the sciences (M, E, I, V, or C) benefits us by reducing some of our danger rates.
  3. Random. May the best pRNG win.

Called by using python undecided.py

import sys
import random

def main():
    print("{0}{1}{2}".format("Q", get_random_science(), get_random_action()))

def get_random_action():
    return random.choice(["M", "E", "I", "V", "C", "Q", "O", "B", "T", "W", "D", "P"])

def get_random_science():
    return random.choice(["M", "E", "I", "V", "C"])


if __name__ == "__main__":
    main()
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I get "TypeError: choice() takes 2 positional arguments but 6 were given" on line 11. \$\endgroup\$ – Mwr247 Jan 26 '16 at 18:41
  • \$\begingroup\$ @Mwr247that would be because I wrote it off the top of my head. Try that. \$\endgroup\$ – ArtOfCode Jan 26 '16 at 18:45
  • \$\begingroup\$ No errors, but still prints nothing. Change your return in main to a print and I think you're good. EDIT: Weird, I'm still getting invalid/blank responses sometimes. \$\endgroup\$ – Mwr247 Jan 26 '16 at 18:48
  • \$\begingroup\$ @Mwr247 helps if I output to STDOUT, I guess. There, I've tested it now. \$\endgroup\$ – ArtOfCode Jan 26 '16 at 18:51
  • \$\begingroup\$ Yup, that works! :D \$\endgroup\$ – Mwr247 Jan 26 '16 at 18:52
1
\$\begingroup\$

Obamacare, Python 3

A little late and a little short, but it should work.

import sys

#get input
stdin = sys.argv[1].split(";")

#unpack input
rnd = stdin[0]
stdin.pop(0)
bot = stdin[0]
stdin.pop(0)
#find self
town = []
for player in stdin:
    if player.split("_")[0] == str(bot):
        town = player.split("_")
        break
#unpack town
healthy = town[1]
infected = town[2]

out = []

#get down to business
if int(infected) < int(healthy):
    out.append("ME")
if int(infected) >= int(healthy):
    out.append("CI")
if int(infected) >= 30:
    out.append("C")
else:
    out.append("T")

sys.stdout.write("".join(out))
| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

InfectionBot

Splitted off into a seperate answer

int lethal=10;
if(round == 1) System.out.print("OOO");
else if (round == 50) System.out.print("CCC");
else{       
  {
    for(int x=0;x<3;x++) {
      if(thisState.getLethalityRate() <=6 && x == 0) {
        if(lethal<50) {
          System.out.print("W");
          lethal = lethal + 3;
          }
        else System.out.print("D");
      } else if(thisState.getLethalityRate()<=2 && x == 1) {
        if(lethal<50) {
          System.out.print("W");
          lethal = lethal + 3;
          }
        else System.out.print("D");
      } else if(thisState.getLethalityRate() ==0 && x == 2) {
        System.out.print("D");
      } else System.out.print("I");
    }
}
}

This Bot is basically an ass trying too flood everyone with his infected by having them migrate and inreasing infection lethality and contagation while lowering his own lethality to 0.

Edit: swapped D and I at the end so it gets more Lethality reduce

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

BipolarBot, Java

BipolarBot starts off playing nice, building up a bit of a population (and letting others do the same).

It then flips and inflicts as much harm on others as possible, while trying to keep its local population from dying out completely. Changed the scoreboard quite a bit when I included it in my local games.

import java.util.ArrayList;
import java.util.List;

public class BipolarBot {

int round;
int phase;
int playerID;
int thisTownID;

List<State> states;
List<State> otherStates;

State thisState;
String action = "";
int cc=0; // command count

public static void main(String[] args){
    new BipolarBot().sleep(args[0].split(";"));
}

private void action(String newAction) {
    action += newAction;
    cc+= newAction.length();
    if (cc>=3) {
        System.out.println(action.substring(0, 3));
        System.exit(0);;
    }
}
private void sleep(String[] args) {

    round = Integer.parseInt(args[0]);
    thisTownID = Integer.parseInt(args[1]);

    states = new ArrayList<>();
    otherStates = new ArrayList<>();

    for (int i = 2; i < args.length; i++){
        states.add(new State(args[i]));
    }

    for (State state : states){
        if (state.isMine()) {
            thisState = state;
        } else {
            otherStates.add(state);
        }
    }

    // Round specific commands
    if (round == 1)                                     { action("B");   }
    if (round == 50)                                    { action("CCC"); }

    if ((round) <= 30)  {
        for (int i=0;i<3;i++){
            if (thisState.getInfectionRate() >= 4)      { action("M"); thisState.infectionRate -= 4;  }
        }

        if (thisState.getInfected() >= 5)   {
            if (thisState.getInfected() < 15)           { action("C");   }
            else if (thisState.getInfected() < 25)      { action("CC");  }
            else                                        { action("CCC"); }
        }

        for (int i=0;i<3;i++){
            if (thisState.getContagionRate() >= 8)      { action("E");  thisState.contagionRate -= 8; }
        }

        for (int i=0;i<3;i++){
            if (thisState.getLethalityRate() >= 4)      { action("I"); thisState.lethalityRate -= 4;  }
        }

        // Nothing else to do, be nice
        action("PPP");
    }

    else {
        for (int i=0;i<3;i++){
            if (thisState.getLethalityRate() >= 4)      { action("I"); thisState.lethalityRate -= 4;  }
        }

        // Nothing else to do, cause trouble.
        action("TTT");

    }

}


private class State {

    private final int ownerId;
    private int healthy;
    private int infected;
    private int dead;
    private int infectionRate;
    private int contagionRate;
    private int lethalityRate;
    private int migrationRate;

    public State(String string) {
        String[] args = string.split("_");
        ownerId = Integer.parseInt(args[0]);
        healthy = Integer.parseInt(args[1]);
        infected = Integer.parseInt(args[2]);
        dead = Integer.parseInt(args[3]);
        infectionRate = Integer.parseInt(args[4]);
        contagionRate = Integer.parseInt(args[5]);
        lethalityRate = Integer.parseInt(args[6]);
        migrationRate = Integer.parseInt(args[7]);
    }

    public int getOwnerId() {
        return ownerId;
    }

    public int getHealthy() {
        return healthy;
    }

    public int getInfected() {
        return infected;
    }

    public int getDead() {
        return dead;
    }

    public int getInfectionRate() {
        return infectionRate;
    }

    public int getContagionRate() {
        return contagionRate;
    }

    public int getLethalityRate() {
        return lethalityRate;
    }

    public int getMigrationRate() {
        return migrationRate;
    }

    public boolean isMine(){
        return getOwnerId() == thisTownID;
    }

}
}
| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Socialist, Python 3

A glorious regime, which thinks all other countries are evil, so they will try to kill them. They do care for their people, so if they get infected they will take action.

Edit:Fixed the type comparison

 from sys import argv 
 data=argv[1].split(";")[2].split("_")
 inf=int(data[2])
 hel=int(data[1])
 dead=int(data[3])
 if inf>29:
     print("CQM") # if there is to many sick cure some, quarantine some, and try to get rid of the disease  
 else:
     if hel<80:
     print("BMV") # if there's few healthy, close our borders, because it's other countries
     else:
         if dead>19:
         print("WMD") # if we have too many dead attack others, but cure ourselves
         else:
         print("TWD") # if none of these are true we want to kill everyone else
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I get an error on line 6 stating that you can't compare integers to strings. \$\endgroup\$ – TheNumberOne Jan 27 '16 at 21:46
  • \$\begingroup\$ Forgot about the type, I will fix that( I got too use to JavaScript an its weird behavior) \$\endgroup\$ – Generic User Jan 27 '16 at 23:13
  • \$\begingroup\$ Fixed, sorry it took so long, I didn't have the time. \$\endgroup\$ – Generic User Feb 15 '16 at 15:17
1
\$\begingroup\$

BackStabber

Acts rather friendly till the end curing its people and being passive, then it goes insane converting global healthy to infected.

from sys import argv
round=int(argv[1].split(";")[0])
if round==1:
    print("VPO")
elif round<11:
    print("VCO")
elif round<23:
    print("VCC")
elif round<35:
    print("VCB")
elif round<41:
    print("VPB")
elif round<46:
    print("CTT")
else:
    print("TTT")
| improve this answer | |
\$\endgroup\$
1
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.