Sign up ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

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 CodeBot challenges, 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. 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
  • 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

127.2   I'm Helping!
110.2   codebots.bots.DefaultCodeBot
99.1    Random bot loves you
98.3    Trust in Trust!
65.2    null
share|improve this question
1  
Is there a way to get your own bots IP address? Also, as it is, I think it might be possible that 2 or more groups of bots can form that will be unable to find the IP addresses of those outside. – TheNumberOne 21 hours ago
    
@TheNumberOne Access to your IP isn't currently possible, though I'm not opposed to the idea. The two groups situation is certainly possible, however, obtaining a new random IPAddress is always possible by clearing your address book. – Nathan Merrill 21 hours ago
    
You should probably allow a bot to access the current turn number. – TheNumberOne 21 hours ago
    
Is the function change permanent or just for the current round? And when is the end of the game? – Nic Robertson 17 hours ago
    
@NicRobertson the function change for the current round (and for the current bot) – Nathan Merrill 16 hours ago

7 Answers 7

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.

share|improve this answer
    
Technically he doesn't fit the specification, because he doesn't exactly return a String for his flag. – TheNumberOne 21 hours ago
2  
null is a string. ;) Just a fancy string. – FlagAsSpam 21 hours ago
    
This made me recognize a flaw in my spec, which has been specified: "all bots should be functionally different than existing entries" – Nathan Merrill 21 hours ago
    
@NathanMerrill Fixed to more closely follow the spec. – TheNumberOne 21 hours ago

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";
    }
}
share|improve this 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!";
    }
}
share|improve this 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();
    }
}
share|improve this 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.

share|improve this 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!"; }
}
share|improve this answer
    
You can select the nth address without needing to do allAddresses(). If you look at my random bot, it is doing random address selection. I've updated your code on Github (for efficiency reasons), but if you feel like it doesn't work, I'm happy to revert it. – Nathan Merrill 1 hour ago

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.put(v.get("ID"),"true");
        if(v.get("hasOurFlag") == "true"){
            ab.remove(ab.getAddress(0));
            v.remove("hasOurFlag");
        }
        return ab.getAddress(0);
    }

    @Override
    public Message sendMessage() {
        return new Message(Message.MessageType.STOP, new IPAddress(getRandom()));
    }

    @Override
    public void processMessage(IPAddress source, Message message) {
        if(message.getType() != Message.MessageType.STOP)
            getAddressBook().add(sounce, AddressBook.AddressType.TO_ATTACK);
    }

    @Override
    public FunctionType selectFunctionToBlock() {
        Variables v = getVariables();
        if(v.get(v.get("ID")) == "true")
            return FunctionType.GET_FLAG;
        return FunctionType.SELECT_FUNCTION_TO_BLOCK;
    }

    @Override
    public IPAddress selectAttackTarget() {
        Variables v = getVariables();
        if(v.get(v.get("ID")) == "true")
            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(v.get("hasOurFlag") == "false")
            v.add("hasOurFlag", "false2");
        else
            v.add("hasOurFlag", "false");
    }

    @Override
    public FunctionType selectFunctionToReplace() {
        Variables v = getVariables();
        if(v.get(v.get("ID")) == "true")
            if(!v.has("hasOurFlag") || v.get("hasOurFlag") == "false")
                return FunctionType.GET_FLAG;
            else if(v.get("hasOurFlag") == "false2")
                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();
    }
}
share

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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