package io.vivarium.audit;
import io.vivarium.core.Action;
import io.vivarium.core.Creature;
import io.vivarium.core.CreatureBlueprint;
import io.vivarium.core.World;
import io.vivarium.serialization.ClassRegistry;
import io.vivarium.serialization.SerializedParameter;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@EqualsAndHashCode(callSuper = true)
@ToString
@SuppressWarnings("serial") // Default serialization is never used for a durable store
public class ActionFrequencyRecord extends AuditRecord
{
static
{
ClassRegistry.getInstance().register(ActionFrequencyRecord.class);
}
// The action tally is a 5x dimensional counter of actions.
// index 1 generation (numeric, index is generation-1)
// index 2 gender (0 is male, 1 is female)
// index 3 gestation (0 is not-pregnant, 2 is pregnant)
// index 4 action (indexes are based on Action.convertActionToInteger)
// index 5 success (0 is failure, 1 is success)
@SerializedParameter
int[][][][][] _tally = new int[16][2][2][Action.values().length][2];
protected ActionFrequencyRecord()
{
}
protected ActionFrequencyRecord(CreatureBlueprint creatureBlueprint)
{
super(creatureBlueprint);
}
@Override
public void record(World world, int tick)
{
for (Creature creature : world.getCreatures())
{
if (creature != null && creature.getBlueprint() == this._trackedCreatureBlueprint)
{
addRecord((int) creature.getGeneration(), creature.getIsFemale(), creature.getGestation() > 0,
creature.getAction(), creature.wasSuccessful());
}
}
}
private void addRecord(int generation, boolean isFemale, boolean isPregnant, Action action, boolean wasSuccessful)
{
while (generation > _tally.length)
{
resizeTally();
}
_tally[generation - 1][isFemale ? 1 : 0][isPregnant ? 1 : 0][Action
.convertActionToInteger(action)][wasSuccessful ? 1 : 0]++;
}
public int getMaximumGeneration()
{
int maximumGeneration = 0;
generation: for (int i = 0; i < _tally.length; i++)
{
for (int j = 0; j < 2; j++)
{
for (int k = 0; k < 2; k++)
{
for (int l = 0; l < Action.values().length; l++)
{
for (int m = 0; m < 2; m++)
{
if (_tally[i][j][k][l][m] > 0)
{
maximumGeneration = i;
continue generation;
}
}
}
}
}
}
return maximumGeneration + 1;
}
public int getRecord(int generation, boolean isFemale, boolean isPregnant, Action action, boolean wasSuccessful)
{
return _tally[generation - 1][isFemale ? 1 : 0][isPregnant ? 1 : 0][Action
.convertActionToInteger(action)][wasSuccessful ? 1 : 0];
}
private void resizeTally()
{
int[][][][][] newTally = new int[_tally.length * 2][2][2][Action.values().length][2];
for (int i = 0; i < _tally.length; i++)
{
for (int j = 0; j < 2; j++)
{
for (int k = 0; k < 2; k++)
{
for (int l = 0; l < Action.values().length; l++)
{
for (int m = 0; m < 2; m++)
{
newTally[i][j][k][l][m] = _tally[i][j][k][l][m];
}
}
}
}
}
_tally = newTally;
}
}