Skip to content

Commit

Permalink
Move creation of DNA to Gene Pool
Browse files Browse the repository at this point in the history
This is long overdue, and it fixes all the problems with the damn DNA
serial ids and the horrible mechanics of their creation and updating.
  • Loading branch information
nusco committed Feb 22, 2015
1 parent 926a3ee commit 90e3290
Show file tree
Hide file tree
Showing 24 changed files with 151 additions and 305 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
public class Egg implements Thing {

public static final double RADIUS = 25;

public static final int INCUBATION_TIME = 500;

private final DNA dna;
private int age = 0;
private Vector position;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@
import org.nusco.narjillos.shared.things.Energy;
import org.nusco.narjillos.shared.things.FoodPiece;
import org.nusco.narjillos.shared.things.Thing;
import org.nusco.narjillos.shared.utilities.RanGen;

/**
* A fully-formed, autonomous creature.
*/
public class Narjillo implements Thing {

static final double MAX_LIFESPAN = 30_000;
private static final int INCUBATION_TIME = 500;

private final Body body;
private final DNA dna;
Expand Down Expand Up @@ -73,16 +71,6 @@ public void feedOn(FoodPiece thing) {
thing.setEater(this);
}

public Egg layEgg(Vector position, RanGen ranGen) {
double percentEnergyToChildren = body.getPercentEnergyToChildren();
double childEnergy = energy.chunkOff(percentEnergyToChildren);
if (childEnergy == 0)
return null;

DNA childDNA = getDNA().copyWithMutations(ranGen);
return new Egg(childDNA, getPosition(), childEnergy, INCUBATION_TIME);
}

@Override
public String getLabel() {
return "narjillo";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.nusco.narjillos.creature.Egg;
import org.nusco.narjillos.creature.Narjillo;
import org.nusco.narjillos.genomics.DNA;
import org.nusco.narjillos.genomics.GenePool;
import org.nusco.narjillos.shared.physics.Segment;
import org.nusco.narjillos.shared.physics.Vector;
import org.nusco.narjillos.shared.things.FoodPiece;
Expand Down Expand Up @@ -75,15 +76,15 @@ public Vector findClosestFoodPiece(Thing thing) {
return target.getPosition();
}

public void tick(RanGen ranGen) {
public void tick(GenePool genePool, RanGen ranGen) {
for (Thing thing : new LinkedList<>(things.getAll("egg")))
tickEgg((Egg) thing);

for (Narjillo narjillo : new LinkedList<>(narjillos))
if (narjillo.isDead())
removeNarjillo(narjillo);
removeNarjillo(narjillo, genePool);

tickNarjillos(ranGen);
tickNarjillos(genePool, ranGen);

if (shouldSpawnFood(ranGen)) {
spawnFood(randomPosition(getSize(), ranGen));
Expand Down Expand Up @@ -153,7 +154,7 @@ private void tickEgg(Egg egg) {
remove(egg);
}

private synchronized void tickNarjillos(RanGen ranGen) {
private synchronized void tickNarjillos(GenePool genePool, RanGen ranGen) {
if (executorService.isShutdown())
return; // we're leaving, apparently

Expand All @@ -165,7 +166,7 @@ private synchronized void tickNarjillos(RanGen ranGen) {
for (Entry<Narjillo, Set<Thing>> entry : narjillosToCollidedFood.entrySet()) {
Narjillo narjillo = entry.getKey();
Set<Thing> collidedFood = entry.getValue();
consume(narjillo, collidedFood, ranGen);
consume(narjillo, collidedFood, genePool, ranGen);
}
}

Expand Down Expand Up @@ -225,20 +226,20 @@ private void updateTargets(Thing food) {
}
}

private void consume(Narjillo narjillo, Set<Thing> foodPieces, RanGen ranGen) {
private void consume(Narjillo narjillo, Set<Thing> foodPieces, GenePool genePool, RanGen ranGen) {
for (Thing foodPiece : foodPieces)
consumeFood(narjillo, (FoodPiece) foodPiece, ranGen);
consumeFood(narjillo, (FoodPiece) foodPiece, genePool, ranGen);
}

private void consumeFood(Narjillo narjillo, FoodPiece foodPiece, RanGen ranGen) {
private void consumeFood(Narjillo narjillo, FoodPiece foodPiece, GenePool genePool, RanGen ranGen) {
if (!things.contains(foodPiece))
return; // race condition: already consumed

remove(foodPiece);

narjillo.feedOn(foodPiece);

layEgg(narjillo, ranGen);
layEgg(narjillo, genePool, ranGen);
updateTargets(foodPiece);
}

Expand All @@ -247,16 +248,21 @@ private void remove(Thing thing) {
things.remove(thing);
}

private void removeNarjillo(Narjillo narjillo) {
private void removeNarjillo(Narjillo narjillo, GenePool genePool) {
notifyThingRemoved(narjillo);
narjillos.remove(narjillo);
narjillo.getDNA().destroy();
genePool.remove(narjillo.getDNA());
}

private void layEgg(Narjillo narjillo, RanGen ranGen) {
Egg egg = narjillo.layEgg(narjillo.getNeckLocation(), ranGen);
if (egg == null) // refused to lay egg
return;
private void layEgg(Narjillo narjillo, GenePool genePool, RanGen ranGen) {
double percentEnergyToChildren = narjillo.getBody().getPercentEnergyToChildren();
double childEnergy = narjillo.getEnergy().chunkOff(percentEnergyToChildren);
if (childEnergy == 0)
return; // refused to lay egg
DNA childDNA = genePool.mutateDNA(narjillo.getDNA(), ranGen);

Vector position = narjillo.getNeckLocation();
Egg egg = new Egg(childDNA, position, childEnergy, Egg.INCUBATION_TIME);
insert(egg);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import org.nusco.narjillos.creature.body.physics.Viscosity;
import org.nusco.narjillos.ecosystem.Ecosystem;
import org.nusco.narjillos.genomics.DNA;
import org.nusco.narjillos.genomics.GenePool;
import org.nusco.narjillos.shared.physics.Vector;
import org.nusco.narjillos.shared.utilities.Chronometer;
Expand Down Expand Up @@ -47,7 +46,6 @@ private void initializeGenePool(boolean trackGenePool) {
return;

genePool.enableTracking();
DNA.setObserver(genePool);
}

public final void timeStamp() {
Expand All @@ -64,10 +62,10 @@ private void populate(Ecosystem ecosystem, String dna) {

if (dna == null) {
for (int i = 0; i < INITIAL_NUMBER_OF_NARJILLOS; i++)
ecosystem.spawnEgg(DNA.random(ranGen), randomPosition(ecosystem.getSize()), ranGen);
ecosystem.spawnEgg(getGenePool().createRandomDNA(ranGen), randomPosition(ecosystem.getSize()), ranGen);
} else {
for (int i = 0; i < INITIAL_NUMBER_OF_NARJILLOS; i++)
ecosystem.spawnEgg(new DNA(dna), randomPosition(ecosystem.getSize()), ranGen);
ecosystem.spawnEgg(getGenePool().createDNA(dna), randomPosition(ecosystem.getSize()), ranGen);
}
}

Expand All @@ -79,7 +77,7 @@ public boolean tick() {
if (ticksChronometer.getTotalTicks() % 1000 == 0)
executePeriodicOperations();

getEcosystem().tick(ranGen);
getEcosystem().tick(genePool, ranGen);
ticksChronometer.tick();
return areThereSurvivors();
}
Expand Down Expand Up @@ -127,13 +125,6 @@ public GenePool getGenePool() {
return genePool;
}

// For serialization only. Don't call this in other situations, if you don't
// want to make the experiment non-deterministic.
public void setGenePool(GenePool genePool) {
this.genePool = genePool;
DNA.setObserver(genePool);
}

@Override
public String toString() {
return "Experiment " + getId();
Expand Down
70 changes: 11 additions & 59 deletions narjillos-core/src/main/java/org/nusco/narjillos/genomics/DNA.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,44 +12,18 @@ public class DNA {

public static final double MUTATION_RATE = 0.055;
private static final int GENE_MUTATION_RANGE = 15;
private static DNAObserver observer = DNAObserver.NULL;

// TODO: This static makes testing difficult. Find another way.
private static long serial = 0;

// for testing
public static long getSerial() {
return serial;
}

public static void setSerial(long value) {
serial = value;
}

private long id;
private final long id;

private final Integer[] genes;

public DNA(String dnaDocument) {
this(new DNADocument(dnaDocument).toGenes());
}

// Only use for deserialization.
public DNA(String dnaDocument, long id) {
public DNA(long id, String dnaDocument) {
this.id = id;
this.genes = clipGenes(new DNADocument(dnaDocument).toGenes());
setId(id);
}

private DNA(Integer... genes) {
this.genes = clipGenes(genes);
setId(serial + 1);
DNA.observer.created(this, null);
}

private DNA(DNA parent, Integer... genes) {
public DNA(long id, Integer[] genes) {
this.id = id;
this.genes = clipGenes(genes);
setId(serial + 1);
DNA.observer.created(this, parent);
}

public long getId() {
Expand All @@ -60,11 +34,7 @@ public Integer[] getGenes() {
return genes;
}

public void destroy() {
DNA.observer.removed(this);
}

public DNA copyWithMutations(RanGen ranGen) {
public DNA copyWithMutations(long id, RanGen ranGen) {
List<Integer[]> resultChromosomes = new LinkedList<>();

DNAIterator iterator = new DNAIterator(this);
Expand All @@ -79,12 +49,12 @@ public DNA copyWithMutations(RanGen ranGen) {
}

Integer[] resultGenes = flatten(resultChromosomes);
return new DNA(this, resultGenes);
return new DNA(id, resultGenes);
}

public static DNA random(RanGen ranGen) {
public static DNA random(long id, RanGen ranGen) {
int size = Chromosome.SIZE * (Math.abs(ranGen.nextInt()) % 10 + 2);
return random(size, ranGen);
return random(id, ranGen, size);
}

// From: http://en.wikipedia.org/wiki/Levenshtein_distance,
Expand Down Expand Up @@ -129,10 +99,6 @@ public int getLevenshteinDistanceFrom(DNA other) {
return v1[otherGenes.length];
}

public static void setObserver(DNAObserver dnaObserver) {
DNA.observer = dnaObserver;
}

@Override
public int hashCode() {
return (int) getId();
Expand All @@ -153,20 +119,6 @@ private Integer[] clipGenes(Integer[] genes) {
return (genes.length > 0) ? clipToByteSize(genes) : new Integer[] { 0 };
}

private void setId(long id) {
this.id = id;
// This complicated mechanism guarantees that even
// after deserializing DNA, the serial will still
// contain the highest id in the system. (But
// if you generate DNA and *then* deserialize
// other DNA, then you might have duplicated
// DNA ids in the system. I assume that you
// will only deserialize DNA before ever creating
// it.
if (id > serial)
serial = id;
}

private Integer[] copyWithMutations(Chromosome chromosome, RanGen ranGen) {
Integer[] result = new Integer[Chromosome.SIZE];
for (int i = 0; i < result.length; i++)
Expand Down Expand Up @@ -210,9 +162,9 @@ private int clipToByteSize(int number) {
return Math.max(0, Math.min(255, number));
}

private static DNA random(int size, RanGen ranGen) {
private static DNA random(long id, RanGen ranGen, int size) {
Integer[] genes = randomGenes(size, ranGen);
return new DNA(genes);
return new DNA(id, genes);
}

private static Integer[] randomGenes(int size, RanGen ranGen) {
Expand Down

This file was deleted.

Loading

0 comments on commit 90e3290

Please sign in to comment.