I'm currently building a library to allow a wide variety of different minority games to be simulated. This involves agents choosing between two choices, say, A and B so the primary functionality of an agent is to choose. An agent wins a point for a turn in the game if it ends up in the minority group after all agents have chosen.
There is obviously an infinite number of different ways that an agent can make their choice and the game investigates the effect of different choice making tactics on the overall wealth of the system. Some ways in which I need agents to be able to choose are:
- completely at random
- by being supplied with a memory so that they can remember the past m minority choices with this memory being used as input into a strategy mapping to a prediction for the minority choice
- by making a prediction and publicising it to a number of other agents who are that agent's 'friends' and then each agents chooses based on some condition about whether or not it trusts its friends.
Now for the programming problem. I currently have an AbstractAgent that encapsulates all this functionality. The thing is some types of agents wont have a list of friends, a set of strategies or a memory etc. At the moment all these abilities are clogging up the base class. I could use an inheritance hierarchy but I think there will be crossover between different classes in the hierarchy i.e., sometimes an agent may have friends and strategies, other times just friends or strategies. Similarly, I could have a collection of interfaces and each different agent implements whatever interfaces it needs, i.e.,
public enum Choice {
A, B
}
public interface Decidable {
private Choice choice;
public Choice getChoice();
public void choose();
}
public interface Strategic {
private StrategyManager strategies;
public StrategyManager getStrategyManager;
public void setStrategyManager(StrategyManager strategyManager);
}
public class CleverAgent implements Decidable, Strategic {
// decides more intelligently using the strategies
}
public class StupidAgent implements Decidable{
public void choose() {
if(Math.random < 0.5) {
return Choice.A
} else {
return Choice.B
}
}
}
Now if I take this route, I can already see numerous interfaces such as Strategic, Decidable, Scorable, Stateful, Memorable and Befriendable. I feel like the actual solution should be a mix between an inheritance hierarchy (I know at least that all agents are Decidable so that should go in a base class) couple with pluggable behaviour.
My question is what is the best approach in this case? Are there any design patterns that I should look into? What are the advantages and disadvantages of each approach especially in terms of how it affects other code in the library as agent state needs to be investigated throughout the game for experimentation purposes?
Any help would be greatly appreciated.