Human and AI subclasses for Player class

  softwareengineering

I am looking to implement two branches of classes in my Java program to distinguish between Human and AI-controlled Players in my game. The game is asynchronous, so players have different methods and behavior depending on which type of player they are selected as at the start of the game. All Players have shared methods, and each Player subclass has unique methods that only they can do. In addition, Human players receive prompts to make decisions while AI players make their choices automatically. There can potentially be an infinite number of Player subclasses, and each one will have a Human and AI version.

Since Java doesn’t have true multiple inheritance, my current solution is to make use of an AI interface that the AI players inherit, and a Human interface that Human players inherit. Each of these interfaces has a unique makeDecision() method for each potential decision that can be made. Rewriting the code from the decision interfaces is fine, as different types of players shouldn’t have the same AI.

Here’s a simple example of my code structure:

public interface AI
{
   int chooseNumber(); 
}

public interface Human 
{
    int chooseNumber();
}

public abstract class Player
{ 
    int score;
    void gainPoint()
    { 
        score++;
    }
}

public class RedPlayer extends Player
{
   void doRedThing();
}

public class RedHumanPlayer extends RedPlayer implements Human
{
    int chooseNumber()
    { 
      //Human chooses number
    }
}

public class RedAIPlayer extends RedPlayer implements AI
{
    int chooseNumber()
    {
       return 3;
    }
}

public class BluePlayer extends Player
{
    void doBlueThing();
}

public class BlueHumanPlayer extends BluePlayer implements Human
{
    int chooseNumber()
    { 
      //Human chooses number
    }
}

public class BlueAIPlayer extends BluePlayer implements AI
{
    int chooseNumber()
    {
       return 4;
    }
}

What I want to determine is if this is the best practice for setting up such a system in Java or if there is perhaps a more optimal strategy. I would rather create a proper blueprint before actually doing all the coding.

5

I think the first misstep in your idea, in the context of the game, is that you aren’t really modeling an AI or a Human, you are modeling a Player. You just happen to have different implementations of Player. From the game’s perspective there should be no difference between a human and an AI player.

The first thing you need to think of is the interface of the Player, what does a player need to do? We could model it as such:

public interface Player {

    int chooseNumber();

    void gainPoint();
}

Then you can have different types of Players:

public interface BluePlayer extends Player{

    void doBlueThing();

}

public interface RedPlayer extends Player{

    void doRedThing();

}

Now, building on @RomanVettner ‘s comment you can implement a RedPlayer class and a BluePlayer class which take a RedStrategy and a BlueStrategy respectively and then provide AI and Human versions of the strategies:

public interface Strategy {
    //interface specification
}

public interface RedStrategy extends Strategy {

    void doRedThing();

}

public interface BlueStrategy extends Strategy {

    void doBlueThing();

}

public abstract class BasePlayer<S extends Strategy> implements Player {

    private S strategy;
    private int score;

    public Player(S strategy){
        this.strategy = strategy;
    }

    public updateStrategy(S newStrategy){
        this.strategy = newStrategy;
    }

    public void gainScore(){
        this.score++;
    }

    protected S strategy(){
        return this.strategy;
    }
}

public class RedPlayerImpl extends BasePlayer<RedStrategy> implements RedPlayer {

    public RedPlayerImpl(RedStrategy strategy){
        super(strategy);
    }

    public void doRedThing(){
        this.strategy().toRedThing();
    }
}

public class RedHumanStrategy implements RedStrategy {
    //implementation for Human
}

public class RedAiStrategy implements RedStrategy {
    //implementation for AI
}

//you get the rest
...

Now the game should only every care about the Player interfaces and does not care about how they are implemented.

Moreover, you may consider to simplify the design even further with this approach and avoid the huge number of child classes of Player. The Red and Blue behaviour as well as the AI and Human behaviours can be simply injected into a general Player object at construction time. This would eliminate the need for the different classes RedPlayer, RedAIPlayer, BlueHumanPlayer, etc.

3

LEAVE A COMMENT