Creating a Prisoner Strategy - AdamVD/Prisoners_Dilemma_Simulator GitHub Wiki

The goal of this simulator is to make the creation of new strategies as easy as possible. To achieve this, new prisoner objects inherit from a superclass named Prisoner. The code for this superclass can be found in src/Strategies/Prisoner.java. To create your own prisoner algorithm, make a new public class with a name of your choice within the src/Strategies package, and extend the Prisoner superclass.

package Strategies;

public class ClassName extends Prisoner {
    ...
}

Required Methods

At a minimum, your class must override only a single method from the superclass. That method is: choose.

choose()

The choose method will be called when the prisoner is asked to make a decision: exploit or comply. It is up to your algorithm to do any necessary processing to determine its decision. The boolean values for the two options are defined by constant fields in the Prisoner superclass. I would strongly recommend using return EXPLOIT; or return COMPLY; to avoid confusion.

From the AlwaysComply strategy:
public class AlwaysComply extends Prisoner {
    @Override
    public boolean choose() {
        return COMPLY;
    }
}

Optional Methods

You may choose to implement any of these methods depending on the level of customization you have implemented in your prisoner strategy. Along with these methods that can be overridden from the superclass, you can create any number of your own methods and fields to run your decision making algorithm and store information.

evolve()

The evolve method will be called when the prisoner survives a generation, and is now being asked to reproduce/evolve. This expects a single new prisoner to be returned that will be added to the pool of prisoners for the next generation. The default implementation of this method within the Prisoner superclass simply calls your strategy's default constructor. If your strategy uses a parametrized constructor, it must also contain a default constructor.

From the MultipleConstructor example:
public class MultipleConstructor extends Prisoner {
    private boolean choice;
    // default
    public MultipleConstructor() {
        // send values to the other constructor (may be randomized).
        this(true);
    }
    // parametrized
    public MultipleConstructor(boolean choice) {
        this.choice = choice;
    }

    @Override
    public Prisoner evolve() {
        return new MultipleConstructor(false);
    }
}

Optionally, if you would like your algorithm to introduce actual evolution, you might choose to initialize your new object using randomly generated parameters that will change the behavior of your prisoner.

notifyOpponentChoice(boolean choice)

This method notifies the prisoner of what the other prisoner's choice was in the previous round. This method is called upon the completion of each round.

From the TitForTat strategy:
public class TitForTat extends Prisoner {
    private boolean prevOppMove = COMPLY;
    @override
    public void notifyOpponentChoice(boolean choice) {
        prevOppMove = choice;
    }
}

notifyGameOver()

This notification method is called on both relevant prisoner objects at the end of a game. It can be used to reset certain fields contained within your object, or any other purpose you see fit. From the TitForTat strategy:
public class TitForTat extends Prisoner {
    private boolean prevOppMove = COMPLY;
    @Override
    public void notifyGameOver() {
        prevOppMove = COMPLY;
    }
}

notifyOtherPrisoner(int prisonerObjectHash)

This notification method is called on both relevant prisoners at the beginning of any game. It will pass in the unique hash code of the other prisoner, which can be used if your strategy needs to "remember" other prisoners. One potential usage is mapping prisoners by their unique hash to a strategy type that is determined by your prisoner. This way your prisoner may "remember" who it faces and adjust its own strategy accordingly.

notifyGenerationOver()

This notification method is called on all living prisoners at the end of a generation (after all games are played). It can be used to reset certain fields contained within your object, or any other purpose you see fit.
⚠️ **GitHub.com Fallback** ⚠️