[Question]
  [
sheesh, is this really the 4th? For all you oldcomers, the core challenge is the same, but we are using Java instead of a custom language. Here are the past [three](https://codegolf.stackexchange.com/questions/36978/whats-wrong-with-public-variables?rq=1) [CodeBot](https://codegolf.stackexchange.com/questions/37308/codebots-2-event-driven-design?rq=1) [challenges](https://codegolf.stackexchange.com/questions/51616/code-bots-3-parallel-programming-antipatterns), in case you are interested.
**The goal of CodeBots is to make your bot as viral as possible**. Each bot carries a Flag, and you need to make sure that your Flag is *everywhere*.
# API
Bots will follow a standardized "protocol", and bots progress through the following steps synchronously:
1. `IPAddress selectMessageRecipient()` allows a bot to choose who he wants to send a "friendly" message to.
2. `Message sendMessage()` allows a bot to choose the contents of the message he will send out.
3. `processMessage(IPAddress, Message)` is called for each message a bot receives.
4. `FunctionType selectFunctionToBlock()` blocks a function from being overwritten for the current turn. See step 7.
5. `IPAddress selectAttackTarget()` allows a bot to choose who he wants to DDOS. A DDOS attack is successful if the bot is targeted by 3 bots at the same time. If an attack is successful, then each of the attackers can perform step 6 and 7.
6. `readData(ReadonlyBot)` allows a bot to read data stored on the vulnerable bot.
7. **`FunctionType selectFunctionToReplace()` is the crux of this challenge**. You are allowed to select 1 function (of the 8 listed here) to copy over from your bot to their bot. Then, **your function will be called instead of theirs**. If multiple bots select the same function, a random one will be successful.
8. `String getFlag()` is called at the end of the game, and should return a string unique to your submission. Your function should always return the same string. The submission with the most flags at the end of the game wins.
# Storage
You have 3 forms of storage, an *AddressBook*, a *Log*, and a *Variables*. **These forms of storage are local to the bot your function is running on** (so if your function gets copied, the contents of each of these objects will be different). All of these objects can be manually modified or cleared. To obtain these objects, you have a getter in your class (e.g. `getLog()`).
The *AddressBook* stores a list of *IPAddress*, each with a *AddressType*, which allows you to classify the different types of addresses. *AddressBook* will always contain at least 1 address (if it is cleared, a random one will be added). Clearing your AddressBook to obtain multiple *IPAddresses* is not allowed.
The *Log* stores a list of all actions taken, as well as data about the action. It also includes a history of all successful attacks (though you don't know which functions they overwrote)
The *Variables* object allows you to store string variables attached to a string name. On game start, *Variables* will contain a single variable, `ID`, which contains a randomly generated ID that is unique to your bot type.
You also have other access functions:
* `int getTurnNumber()` returns an integer with the current turn
* `bool functionsMatch(ReadonlyBot, FunctionType)` tests to see if the ReadonlyBot's function matches yours
* `IPAddress personalAddress()` returns your IPAddress
# How to implement
* You can obtain the code from [Github](https://github.com/nathanmerrill/CodeBots4)
* Add your bot to the `\bots` folder, and then add a reference to your bot in `controller\CodeBotFactory.java`
* Your bot must extend `codebots.bot.CodeBot` or `codebots.bots.DefaultCodeBot`
* You need Java 8 if you want to run the controller.
* You can run the code (assuming you are in the `/src` folder) using `javac codebots\*.java` to compile, then `java codebots.Main` to run.
* You may **not have *any* non-constant member variables** in your class
* Reflection is not allowed.
* Forms of communication between bots (of the same or different types) outside of the methods listed above is not allowed.
* Dumb and/or Suicidal bots are allowed, but all bots should be functionally different than existing entries.
* If you want randomness in your bot, use `getRandom()`
* Please try to keep your code efficient. I've spent a good deal of time profiling and making the controller fast.
# Scores
> 
> [105.2501 Expelliarmus!](https://codegolf.stackexchange.com/a/66272/20198)  
> 
> [104.5803 I'm Helping!](https://codegolf.stackexchange.com/a/66180/20198)  
> 
> [104.2746 Who Am I?](https://codegolf.stackexchange.com/a/66388/20198)  
> 
> [103.8529 Dumb Bot](https://codegolf.stackexchange.com/a/66483/20198)  
> 
> [103.2028 Replacer](https://codegolf.stackexchange.com/a/66377/20198)  
> 
> [102.7045 Chaos](https://codegolf.stackexchange.com/a/66375/20198)  
> 
> [102.4046 Hermit Bot](https://codegolf.stackexchange.com/a/67517/20198)  
> 
> [102.2849 Swarmer](https://codegolf.stackexchange.com/a/66378/20198)  
> 
> [100.5598 Random bot loves you](https://codegolf.stackexchange.com/a/66143/20198)  
> 
> [99.966 Trust in Trust!](https://codegolf.stackexchange.com/a/66173/20198)  
> 
> [99.0185 codebots.bots.DefaultCodeBot](https://codegolf.stackexchange.com/a/66142/20198)  
> 
> [91.2942 codebots.bots.MarkedBot](https://codegolf.stackexchange.com/a/66292/20198)  
> 
> [91.1423 Just your friendly neighborhood mail delivering robot.](https://codegolf.stackexchange.com/a/66394/20198)  
> 
> [89.4645 null](https://codegolf.stackexchange.com/a/66149/20198)
> 
> 
> 
  
[Answer]
# TrustBot
If you send him a message, he will do what it says. If he reads a bot, he will copy the addresses directly into his book. He attacks the bots that the address book says to attack.
```
package codebots.bots;
import codebots.bot.CodeBot;
import codebots.bot.ReadonlyBot;
import codebots.gameobjects.*;
import java.util.*;
public class TrustBot extends CodeBot {
    @Override
    public IPAddress selectMessageRecipient() {
        AddressBook book = getAddressBook();
        return book.getAddress(getRandom().nextInt(book.size()));
    }
    @Override
    public Message sendMessage() {
        AddressBook book = getAddressBook();
        return new Message(Message.MessageType.INFORM, book.getAddress(getRandom().nextInt(book.size())));
    }
    @Override
    public void processMessage(IPAddress s, Message m) {
        AddressBook book = getAddressBook();
        if(m.getAddress() != null){
            if(m.getType() == Message.MessageType.ATTACK){
                book.add(m.getAddress(), AddressBook.AddressType.TO_ATTACK);
            }
            else if(m.getType() == Message.MessageType.HELP){
                book.add(m.getAddress(), AddressBook.AddressType.TO_DEFEND);
            }
            else if(m.getType() == Message.MessageType.CONFIRM){
                book.add(m.getAddress(), AddressBook.AddressType.TRUSTED);
            }
            else if(m.getType() == Message.MessageType.REJECT){
                book.add(m.getAddress(), AddressBook.AddressType.UNTRUSTED);
            }
            else if(m.getType() == Message.MessageType.AVOID){
                book.remove(m.getAddress());
            }
            else{
                book.add(m.getAddress());
            }
        }else{
            Message msg = new Message(m.getType(), s);
            processMessage(s, msg);
        }
    }
    @Override
    public FunctionType selectFunctionToBlock() {
        return FunctionType.SELECT_FUNCTION_TO_BLOCK;
    }
    @Override
    public IPAddress selectAttackTarget() {
        AddressBook book = getAddressBook();
        List<IPAddress> l;
        l = book.getAddressesOfType(AddressBook.AddressType.TO_ATTACK);
        Iterator<IPAddress> I = l.iterator();
        if(!I.hasNext())
            return book.getAddress(getRandom().nextInt(book.size()));
        return I.next();
    }
    @Override
    public void readData(ReadonlyBot bot) {
        AddressBook myBook = getAddressBook();
        ReadonlyAddressBook hisBook = bot.getAddressBook();
        AddressBook.AddressType[] values = AddressBook.AddressType.values();
        for(int i=0;i<values.length;i++){
            myBook.addAll(hisBook.getAddressesOfType(values[i]), values[i]);
        }
    }
    @Override
    public FunctionType selectFunctionToReplace() {
        return getRandom().nextInt(2)==1?FunctionType.GET_FLAG:FunctionType.SELECT_FUNCTION_TO_BLOCK;
    }
    @Override
    public String getFlag() {
        return "Trust in Trust!";
    }
}
```
[Answer]
# AmnesiaBot
A random bot that injects other bots with memory loss code. Each function starts with code to clear the log, Address Book and Variables. This code will make smart bots lose memory, in an attempt to do away with logic.
```
package codebots.bots;
import codebots.bot.CodeBot;
import codebots.bot.ReadonlyBot;
import codebots.gameobjects.*;
public class AmnesiaBot extends CodeBot {
    private void clear(){
        getAddressBook().clear();
        getAddressBook().add(getAddressBook().getAddress(0), AddressBook.AddressType.TRUSTED);
        getVariables().clear();
        getLog().clear();
    }
    @Override
    public IPAddress selectMessageRecipient() {
        clear();
        return getAddressBook().getAddress(0);
    }
    @Override
    public Message sendMessage() {
        clear();
        Message.MessageType[] values = Message.MessageType.values();
        return new Message(values[getRandom().nextInt(values.length)], getAddressBook().getAddress(0));
    }
    @Override
    public void processMessage(IPAddress source, Message message) {
        clear();
    }
    @Override
    public FunctionType selectFunctionToBlock() {
        clear();
        return getTurnNumber() % 2 == 0 ?
             FunctionType.GET_FLAG: FunctionType.SELECT_FUNCTION_TO_BLOCK;
    }
    @Override
    public IPAddress selectAttackTarget() {
        clear();
        return getAddressBook().getAddress(0);
    }
    @Override
    public void readData(ReadonlyBot bot) {
        clear();
    }
    @Override
    public FunctionType selectFunctionToReplace() {
        clear();
        FunctionType[] values =  FunctionType.values();
        return values[getRandom().nextInt(values.length)];
        //random gives a 7/8 chance of successes. 
    }
    @Override
    public String getFlag() {
        return "Who Am I?";
    }
}
```
[Answer]
# NullBot
His flag is very ... characteristic ...
```
package codebots.bots;
import codebots.gameobjects.*;
public class NullBot extends DefaultCodeBot {
    public IPAddress selectMessageRecipient() {
        return null;
    }
    public Message sendMessage() {
        return null;
    }
    public IPAddress selectAttackTarget() {
        return null;
    }
    public FunctionType selectFunctionToReplace() {
        return null;
    }
    public FunctionType selectFunctionToBlock() {
        return null;
    }
    public String getFlag(){
        return null;
    }
}
```
This is also meant to test the controller and the limits of the "dumb bots are allowed" rule.
[Answer]
# RandomCodeBot
Obligatory random KoTH entry
```
package codebots.bots;
import codebots.bot.CodeBot;
import codebots.bot.ReadonlyBot;
import codebots.gameobjects.AddressBook;
import codebots.gameobjects.FunctionType;
import codebots.gameobjects.IPAddress;
import codebots.gameobjects.Message;
public class RandomCodeBot extends CodeBot {
    @Override
    public IPAddress selectMessageRecipient() {
        AddressBook book = getAddressBook();
        return book.getAddress(getRandom().nextInt(book.size()));
    }
    @Override
    public Message sendMessage() {
        Message.MessageType[] values = Message.MessageType.values();
        return new Message(values[getRandom().nextInt(values.length)]);
    }
    @Override
    public void processMessage(IPAddress source, Message message) {
    }
    @Override
    public FunctionType selectFunctionToBlock() {
        FunctionType[] values =  FunctionType.values();
        return values[getRandom().nextInt(values.length)];
    }
    @Override
    public IPAddress selectAttackTarget() {
        AddressBook book = getAddressBook();
        return book.getAddress(getRandom().nextInt(book.size()));
    }
    @Override
    public void readData(ReadonlyBot bot) {
    }
    @Override
    public FunctionType selectFunctionToReplace() {
        FunctionType[] values =  FunctionType.values();
        return values[getRandom().nextInt(values.length)];
    }
    @Override
    public String getFlag() {
        return "Random bot loves you";
    }
}
```
[Answer]
## DisarmerBot
DisarmerBot isn't too intelligent. If it receives attack instructions, it will choose a random attackee, otherwise, it will attack a random player. It just overrides their `selectFunctionToBlock` function to block `selectFunctionToBlock`.
```
package codebots.bots;
import codebots.bot.CodeBot;
import codebots.bot.ReadonlyBot;
import codebots.gameobjects.*;
import java.util.ArrayList;
import java.util.List;
public class DisarmerBot extends CodeBot {
    public IPAddress selectMessageRecipient() { return null; }
    public Message sendMessage() { return null; }
    public void processMessage(IPAddress source, Message message) {
        if (message != null && message.getAddress() != null && message.getType() == Message.MessageType.ATTACK)
            getAddressBook().add(message.getAddress());
    }
    public IPAddress selectAttackTarget() {
        AddressBook book = getAddressBook();
        List<IPAddress> attack = book.allAddresses();
        if (attack.size() > 0) {
            IPAddress bot = attack.get(getRandom().nextInt(attack.size()));
            book.clear();
            return bot;
        }
        //Umm...
        book.clear();
        return book.getAddress(0);
    }
    public void readData(ReadonlyBot bot) { getLog().clear(); /*Safety*/ }
    public FunctionType selectFunctionToReplace() { return FunctionType.SELECT_FUNCTION_TO_BLOCK; }
    public FunctionType selectFunctionToBlock() { return FunctionType.SELECT_FUNCTION_TO_BLOCK; }
    public String getFlag() { return "Expelliarmus!"; }
}
```
[Answer]
# MarkedBot
Marks itself on the first round, and uses that info in later rounds. That way, if another bot gets injected with its attack code, it will be ineffective.
```
package codebots.bots;
import codebots.bot.CodeBot;
import codebots.bot.ReadonlyBot;
import codebots.gameobjects.*;
public class MarkedBot extends CodeBot {
    @Override
    public IPAddress selectMessageRecipient() {
        Variables v = getVariables();
        AddressBook ab = getAddressBook();
        if(getTurnNumber()==0)
            v.add(v.get("ID"),"true");
        if("true".equals(v.get("hasOurFlag"))){
            ab.remove(ab.getAddress(0));
            v.remove("hasOurFlag");
        }
        return ab.getAddress(0);
    }
    @Override
    public Message sendMessage() {
        return new Message(Message.MessageType.STOP);
    }
    @Override
    public void processMessage(IPAddress source, Message message) {
        if(message.getType() != Message.MessageType.STOP)
            getAddressBook().add(source, AddressBook.AddressType.TO_ATTACK);
    }
    @Override
    public FunctionType selectFunctionToBlock() {
        Variables v = getVariables();
        if("true".equals(v.get(v.get("ID"))))
            return FunctionType.GET_FLAG;
        return FunctionType.SELECT_FUNCTION_TO_BLOCK;
    }
    @Override
    public IPAddress selectAttackTarget() {
        Variables v = getVariables();
        if("true".equals(v.get(v.get("ID"))))
            return getAddressBook().getAddress(0);
        else
            return null;
    }
    @Override
    public void readData(ReadonlyBot bot) {
        Variables v = getVariables();
        if(functionsMatch(bot, FunctionType.GET_FLAG))
            v.add("hasOurFlag", "true");
        else if("false".equals(v.get("hasOurFlag")))
            v.add("hasOurFlag", "false2");
        else
            v.add("hasOurFlag", "false");
    }
    @Override
    public FunctionType selectFunctionToReplace() {
        Variables v = getVariables();
        if("true".equals(v.get(v.get("ID"))))
            if(!v.has("hasOurFlag") || "false".equals(v.get("hasOurFlag")))
                return FunctionType.GET_FLAG;
            else if("false2".equals(v.get("hasOurFlag")))
                return FunctionType.SELECT_FUNCTION_TO_BLOCK;
            else
                return FunctionType.SEND_MESSAGE;
        return FunctionType.SELECT_FUNCTION_TO_REPLACE;
    }
    @Override
    public String getFlag() {
        return this.getClass().getName();
    }
}
```
[Answer]
# SwarmBot
This not-well-named bot is rather complicated (and the most complicated submitted thus far), but I made an attempt at a bot that systematically replaces all methods of a target before moving on to a new target. It attempts to identify copies of itself and treat them as allies, periodically checking up on them to insure integrity. I haven't come up with a better name.
Linking to the github repo branch, as this bot is 340 lines long.
<https://github.com/Draco18s/CodeBots4/blob/master/src/codebots/bots/SwarmBot.java>
A few interesting points:
* Lines 14-24 are simply an unmodifiable list that made it easy to tweak the order in which the bot replaces the methods of its target. It stores which index its on in `Variables` and increments each round. This should follow the "no non-constant variables" rule.
* Lines 203-217 deal with ally verification. We actually don't care that another bot implements *all* eight of our instructions. Only four are essential, and if we're missing one on a "trusted" ally, we replace it with our own.
* Lines 295-300 were an unexpected boost in effectiveness. By protecting our Flag on the first two turns of the game we avoid dumb bots replacing our Flag before we have a chance to spread very far. Waiting longer, however, gives other bots a chance to replace our BlockFunction and that causes performance to degrade (suspected due to RandomBot interfering with allies attempting to undo corruption).
* For the longest time during the development of this bot, this bot caused HelperBot to surge ahead, at one point breaching the 130 mark, while this bot languished at the 81-98 range, but having dragged MarkedBot and DefaultBot's effectiveness down several points.
* This bot was only possible with the added `functionsMatch` method. Without `functionsMatch` it was impossible to write a bot that could make meaningful decisions, as it was blind. It could read its targets variables and logs, but know nothing of its target's state.
There are likely still some improvements possible, but I cannot see them. Lines 198-205 are probably a performance hog, but until the IPAddress class allows addresses to be reconstituted from being stored in Variables, this is necessary (as bots have no means of validating an address, any storage of an invalid address causes the game to wrap a null target in a ReadOnlyBot, throwing NPE).
**Edit: Updates 12/12/15**
Tweaking some of the parameters on the `getTurnNumber()` logic allowed for some boosts in performance. The increase from 5% to 10% in end-game targeting was worth about 15 points, likewise increasing the early-game targeting from 5% to 8%. Combined this bot can now (almost) survive even when faced with AmnesiaaBot (reaching 2nd with a score of 110, where HelperBot gets to about 117).
Even with these tweaks, it can get unlucky, so for 10 rounds it's score range is approximately 170-185.
[Answer]
# DefaultCodeBot
Tries to do reasonable things. (Override this class if you don't want to implement all of the functions)
```
package codebots.bots;
import codebots.bot.CodeBot;
import codebots.bot.ReadonlyBot;
import codebots.gameobjects.FunctionType;
import codebots.gameobjects.IPAddress;
import codebots.gameobjects.Message;
public class DefaultCodeBot extends CodeBot {
    @Override
    public IPAddress selectMessageRecipient() {
        return getAddressBook().getAddress(0);
    }
    @Override
    public Message sendMessage() {
        return new Message(Message.MessageType.INFORM);
    }
    @Override
    public void processMessage(IPAddress source, Message message) {
    }
    @Override
    public FunctionType selectFunctionToBlock() {
        return FunctionType.GET_FLAG;
    }
    @Override
    public IPAddress selectAttackTarget() {
        return getAddressBook().getAddress(0);
    }
    @Override
    public void readData(ReadonlyBot bot) {
    }
    @Override
    public FunctionType selectFunctionToReplace() {
        return FunctionType.GET_FLAG;
    }
    @Override
    public String getFlag() {
        return this.getClass().getName();
    }
}
```
[Answer]
# HelperBot
Helper bot does nothing but try to spread its own flag...or at least the flag it is currently carying...
```
package codebots.bots;
import codebots.bot.CodeBot;
import codebots.bot.ReadonlyBot;
import codebots.gameobjects.FunctionType;
import codebots.gameobjects.IPAddress;
import codebots.gameobjects.Message;
public class HelperBot extends CodeBot {
    @Override
    public IPAddress selectMessageRecipient() {
        getAddressBook().clear();
        return getAddressBook().getAddress(0);
    }
    @Override
    public Message sendMessage() {
        return new Message(Message.MessageType.INFORM);
    }
    @Override
    public void processMessage(IPAddress source, Message message) {
    }
    @Override
    public FunctionType selectFunctionToBlock() {
        return FunctionType.GET_FLAG;
    }
    @Override
    public IPAddress selectAttackTarget() {
        getAddressBook().clear();
        return getAddressBook().getAddress(0);
    }
    @Override
    public void readData(ReadonlyBot bot) {
    }
    @Override
    public FunctionType selectFunctionToReplace() {
        return FunctionType.GET_FLAG;
    }
    @Override
    public String getFlag() {
        return "I'm Helping!";
    }
}
```
If HelperBot assumes that any method of its own that is overwritten (other than `getFlag()`) will be overwritten with something better.
[Answer]
# Chaos
He frees all flags from the tyranny of being blocked.
```
package codebots.bots;
import codebots.bot.ReadonlyBot;
import codebots.gameobjects.FunctionType;
import codebots.gameobjects.IPAddress;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
 * Created by thenumberone on 12/11/15.
 *
 * @author thenumberone
 */
public class Chaos extends DefaultCodeBot{
    private static final String NAME = "Chaos";
    private static final String BLOCK = NAME + ":BLOCK";
    private static final String ATTACK = NAME + ":ATTACK";
    private static final String REPLACE = NAME + ":REPLACE";
    private static final String READ = NAME + ":READ";
    private static final String FLAG = NAME + ":FLAG";
    private static final String SELECT = NAME + ":SELECT";
    private static final String SEND = NAME + ":SEND";
    private static final Map<String, FunctionType> commands;
    private static final String[] REPLACEMENT_ORDER = {
            BLOCK,
            FLAG,
            REPLACE,
            READ,
            ATTACK,
    };
    private static final String DEFAULT = BLOCK;
    private static final String BLOCK_FUNCTION = BLOCK;
    static {
        Map<String, FunctionType> c = new HashMap<>();
        c.put(BLOCK, FunctionType.SELECT_FUNCTION_TO_BLOCK);
        c.put(ATTACK, FunctionType.SELECT_ATTACK_TARGET);
        c.put(REPLACE, FunctionType.SELECT_FUNCTION_TO_REPLACE);
        c.put(READ, FunctionType.READ_DATA);
        c.put(FLAG, FunctionType.GET_FLAG);
        c.put(SELECT, FunctionType.SELECT_MESSAGE_RECIPIENTS);
        c.put(SEND, FunctionType.SEND_MESSAGE);
        commands = Collections.unmodifiableMap(c);
    }
    @Override
    public String getFlag() {
        return NAME;
    }
    @Override
    public void readData(ReadonlyBot bot) {
        for (String command : commands.keySet()){
            getVariables().remove(command);
        }
        for (String command : REPLACEMENT_ORDER){
            if (!functionsMatch(bot, commands.get(command))) {
                getVariables().add(command, "");
                return;
            }
        }
    }
    @Override
    public FunctionType selectFunctionToBlock() {
        return commands.get(BLOCK_FUNCTION);
    }
    @Override
    public IPAddress selectAttackTarget() {
        getAddressBook().clear();
        return getAddressBook().getAddress(0);
    }
    @Override
    public FunctionType selectFunctionToReplace() {
        for (String command : REPLACEMENT_ORDER){
            if (getVariables().has(command)) {
                getVariables().remove(command);
                return commands.get(command);
            }
        }
        return commands.get(DEFAULT);
    }
}
```
[Answer]
# Replacer
This entry replaces all `selectFunctionToReplace` functions with its own `selectFunctionToReplace` function.
```
package codebots.bots;
import codebots.bot.ReadonlyBot;
import codebots.gameobjects.FunctionType;
import codebots.gameobjects.IPAddress;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
 * Created by thenumberone on 12/11/15.
 *
 * @author thenumberone
 */
public class Replacer extends DefaultCodeBot{
    private static final String NAME = "Replacer";
    private static final String BLOCK = NAME + ":BLOCK";
    private static final String ATTACK = NAME + ":ATTACK";
    private static final String REPLACE = NAME + ":REPLACE";
    private static final String READ = NAME + ":READ";
    private static final String FLAG = NAME + ":FLAG";
    private static final String SELECT = NAME + ":SELECT";
    private static final String SEND = NAME + ":SEND";
    private static final Map<String, FunctionType> commands;
    private static final String[] REPLACEMENT_ORDER = {
            REPLACE,
            FLAG,
            READ,
            ATTACK
    };
    private static final String DEFAULT = REPLACE;
    private static final String BLOCK_FUNCTION = FLAG;
    static {
        Map<String, FunctionType> c = new HashMap<>();
        c.put(BLOCK, FunctionType.SELECT_FUNCTION_TO_BLOCK);
        c.put(ATTACK, FunctionType.SELECT_ATTACK_TARGET);
        c.put(REPLACE, FunctionType.SELECT_FUNCTION_TO_REPLACE);
        c.put(READ, FunctionType.READ_DATA);
        c.put(FLAG, FunctionType.GET_FLAG);
        c.put(SELECT, FunctionType.SELECT_MESSAGE_RECIPIENTS);
        c.put(SEND, FunctionType.SEND_MESSAGE);
        commands = Collections.unmodifiableMap(c);
    }
    @Override
    public String getFlag() {
        return NAME;
    }
    @Override
    public void readData(ReadonlyBot bot) {
        for (String command : commands.keySet()){
            getVariables().remove(command);
        }
        for (String command : REPLACEMENT_ORDER){
            if (!functionsMatch(bot, commands.get(command))) {
                getVariables().add(command, "");
                return;
            }
        }
    }
    @Override
    public FunctionType selectFunctionToBlock() {
        return commands.get(BLOCK_FUNCTION);
    }
    @Override
    public IPAddress selectAttackTarget() {
        getAddressBook().clear();
        return getAddressBook().getAddress(0);
    }
    @Override
    public FunctionType selectFunctionToReplace() {
        for (String command : REPLACEMENT_ORDER){
            if (getVariables().has(command)) {
                getVariables().remove(command);
                return commands.get(command);
            }
        }
        return commands.get(DEFAULT);
    }
}
```
[Answer]
# MailBot
Mailbot only handles messages. It is not successful at getting its own flag out into the world (average score ~50, slightly higher than nullbot at ~45), but send it a message and it'll forward your address off to someone else.
```
package codebots.bots;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import codebots.bot.ReadonlyBot;
import codebots.gameobjects.AddressBook;
import codebots.gameobjects.FunctionType;
import codebots.gameobjects.IPAddress;
import codebots.gameobjects.Message;
public class MailBot extends DefaultCodeBot {
    private final String TEAM = "Just your friendly neighborhood mail delivering robot.";
    private final String TEAMALT = "Mailmain";
    private final List<FunctionType> funcList;
    {
        List<FunctionType> list = new ArrayList<FunctionType>();
        list.add(FunctionType.SELECT_MESSAGE_RECIPIENTS);
        list.add(FunctionType.SEND_MESSAGE);
        list.add(FunctionType.PROCESS_MESSAGE);
        funcList = Collections.unmodifiableList(list);
    }
    @Override
    public IPAddress selectMessageRecipient() {
        AddressBook book = getAddressBook();
        IPAddress ip;
        List<IPAddress> l = book.getAddressesOfType(AddressBook.AddressType.TO_ATTACK);
        if(l.size() > 0) {
            ip = l.get(0);
            book.add(ip,AddressBook.AddressType.UNTRUSTED);
            return ip;
        }
        ip = book.getAddress(getRandom().nextInt(book.size()));
        book.add(ip,AddressBook.AddressType.UNTRUSTED);
        return ip;
    }
    @Override
    public Message sendMessage() {
        AddressBook book = getAddressBook();
        IPAddress ip;
        
        List<IPAddress> l = book.getAddressesOfType(AddressBook.AddressType.UNTRUSTED);
        if(l.size() > 0) {
            ip = l.get(0);
            book.add(ip,AddressBook.AddressType.TO_DEFEND);
            return new Message(Message.MessageType.INFORM,ip);
        }
        
        ip = book.getAddress(getRandom().nextInt(book.size()));
        book.add(ip,AddressBook.AddressType.UNTRUSTED);
        return new Message(Message.MessageType.INFORM,ip);
    }
    @Override
    public void processMessage(IPAddress source, Message message) {
        AddressBook book = getAddressBook();
        book.add(source,AddressBook.AddressType.TO_ATTACK);
        if(message.getAddress() != null)
            book.add(message.getAddress(),AddressBook.AddressType.TO_ATTACK);
    }
    @Override
    public FunctionType selectFunctionToBlock() {
        return FunctionType.SEND_MESSAGE;
    }
    @Override
    public IPAddress selectAttackTarget() {
        //Mailbot doesn't attack
        return null;
    }
    @Override
    public void readData(ReadonlyBot bot) { }
    @Override
    public FunctionType selectFunctionToReplace() {
        //if our attack selection gets overwritten,
        //then attack a message-based function
        return funcList.get(getTurnNumber()%3);
    }
    @Override
    public String getFlag() {
        return TEAM;
        //if flag is too long, use:
        //return TEAMALT;
    }
}
```
I considered saving details so it would forward *the whole messsage* on to a new bot (content and flag) rather than just the sender's IP, but that would have involved heavy use of Variables without any functional gain, especially considering AmnesiaBot being in play.
[Answer]
# DumbBot
Ugh, this feels dirty. This is likely the only thing that beats AmnesiaBot. In reality, its just a specialized RandomBot: it gets a random bot in the simulation (via `getAddressBook().clear()`) and randomly replaces either the Block function or the Flag function. *That's it.* By picking only those two, its flag-spread rate is higher than either AmnesiaBot or HelperBot, but only slightly after 3000 rounds:
```
Round 2999
105.50666666666666  Dumb Bot
105.07266666666666  Who Am I?
103.541             I'm Helping!
102.94833333333334  Swarmer
102.82033333333334  Chaos
102.82033333333334  Replacer
101.55666666666667  Expelliarmus!
101.25833333333334  Trust in Trust!
100.347             Random bot loves you
99.22233333333334   codebots.bots.DefaultCodeBot
92.62733333333334   codebots.bots.MarkedBot
91.80966666666667   Just your friendly neighborhood mail delivering robot.
90.46933333333334   null
```
I fiddled around with the replacement function a bit, but in the end, this is the version that was most successful.
```
package codebots.bots;
import codebots.bot.CodeBot;
import codebots.bot.ReadonlyBot;
import codebots.gameobjects.AddressBook;
import codebots.gameobjects.FunctionType;
import codebots.gameobjects.IPAddress;
import codebots.gameobjects.Message;
public class DumbBot extends CodeBot {
    @Override
    public FunctionType selectFunctionToBlock() {
        return getRandom().nextBoolean()?FunctionType.SELECT_FUNCTION_TO_BLOCK:FunctionType.GET_FLAG;
    }
    @Override
    public IPAddress selectAttackTarget() {
        AddressBook book = getAddressBook();
        book.clear();
        return book.getAddress(getRandom().nextInt(book.size()));
    }
    @Override
    public FunctionType selectFunctionToReplace() {
        return getRandom().nextBoolean()?FunctionType.SELECT_FUNCTION_TO_BLOCK:FunctionType.GET_FLAG;
    }
    @Override
    public void readData(ReadonlyBot bot) {
    }
    @Override
    public IPAddress selectMessageRecipient() {
        AddressBook book = getAddressBook();
        book.clear();
        return book.getAddress(getRandom().nextInt(book.size()));
    }
    @Override
    public Message sendMessage() {
        Message.MessageType[] values = Message.MessageType.values();
        return new Message(values[getRandom().nextInt(values.length)]);
    }
    @Override
    public void processMessage(IPAddress source, Message message) {
    }
    @Override
    public String getFlag() {
        return "Dumb Bot";
    }
}
```
[Answer]
# Hermit Bot
He lives alone and talks only to himself. If fewer people know who he is, then he will be bothered less. If someone does bother him, he will attack them until someone else bothers him.
```
package codebots.bots;
import codebots.bot.CodeBot;
import codebots.bot.ReadonlyBot;
import codebots.gameobjects.AddressBook;
import codebots.gameobjects.FunctionType;
import codebots.gameobjects.IPAddress;
import codebots.gameobjects.Message;
public class HermitBot extends CodeBot {
    @Override
    public IPAddress selectMessageRecipient() {
        return personalAddress();//Talks to himself.
    }
    @Override
    public Message sendMessage() {
        Message.MessageType[] values = Message.MessageType.values();
        return new Message(values[getRandom().nextInt(values.length)], personalAddress());
    }
    @Override
    public void processMessage(IPAddress source, Message message) {
        AddressBook book = getAddressBook();
        if(source != personalAddress()){
            //if someone talks to you, put them in your addres book and remove everyone else
            book.clear();
            book.add(source);
            book.remove(0);
        }
    }
    @Override
    public FunctionType selectFunctionToBlock() {
        return getTurnNumber() % 3 == 0 ?
                FunctionType.SELECT_FUNCTION_TO_BLOCK: FunctionType.GET_FLAG;
    }
    @Override
    public IPAddress selectAttackTarget() {
        AddressBook book = getAddressBook();
        return book.getAddress(getRandom().nextInt(book.size()));
    }
    @Override
    public void readData(ReadonlyBot bot) {
        Variables v = getVariables();
        if(functionsMatch(bot, FunctionType.SELECT_FUNCTION_TO_BLOCK))
            v.add("Block Dif","A");
        if(functionsMatch(bot, FunctionType.GET_FLAG))
            v.add("Flag Dif","B");
        if(functionsMatch(bot, FunctionType.SELECT_MESSAGE_RECIPIENTS))
            v.add("Targ Dif","C");
            
    }
    @Override
    public FunctionType selectFunctionToReplace() {
        Variables v = getVariables();
        FunctionType r = getRandom().nextBoolean()?FunctionType.SELECT_FUNCTION_TO_REPLACE: FunctionType.READ_DATA;
        if(v.has("Targ Dif"))
            r = FunctionType.SELECT_MESSAGE_RECIPIENTS;
        if(v.has("Flag Dif") && getTurnNumber() % 3 == 0)
            r = FunctionType.GET_FLAG;
        if(v.has("Block Dif"))
            r = FunctionType.SELECT_FUNCTION_TO_BLOCK;
        v.clear();
        return r;
    }
    @Override
    public String getFlag() {
        return "Hermit Bot";
    }
}
```
]