Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c525708
decision making for lions improved - a smarter moving logic for lions…
bkarimii Aug 24, 2025
004507b
decision making for goats improved - a smarter moving logic for goats…
bkarimii Aug 24, 2025
f3e7d15
DNA and common traits added to animals
bkarimii Aug 24, 2025
bd7f4c2
typo fixed
bkarimii Aug 24, 2025
2d3f841
traits implemented for Goats
bkarimii Aug 24, 2025
f4991f9
traits implemented for Lions
bkarimii Aug 24, 2025
ea11087
...
bkarimii Aug 24, 2025
e0c116e
animals inherit traits from their parents
bkarimii Aug 25, 2025
cbaf8ee
fleeing power trait added to Goat class - packing affinity implemente…
bkarimii Aug 25, 2025
d4c69ae
huntingPower trait added for lions
bkarimii Aug 25, 2025
ba87cb5
gestation period implemented for animals
bkarimii Aug 27, 2025
d1e7578
gestation and smarter wander implemented for goats
bkarimii Aug 27, 2025
4fc10e6
gestation a implemented for lions
bkarimii Aug 27, 2025
6db603d
each species has its own speed
bkarimii Aug 28, 2025
8a9e70a
updated to ignore all csv files
bkarimii Sep 2, 2025
f0da4f2
DNA class created to store all type of traits for animals
bkarimii Sep 2, 2025
40553f9
Animal adjusted to store traits, based on the new logic, in DNA class
bkarimii Sep 2, 2025
f719def
Goat and Lion updated with new DNA logic
bkarimii Sep 2, 2025
21a2a53
traits in animal DNA is written in a csv file
bkarimii Sep 2, 2025
9ccd302
redundant
bkarimii Sep 2, 2025
8e7b1d4
append=false in writing traits to csv
bkarimii Sep 2, 2025
a0bd613
values rounded to 2 decimal points
bkarimii Sep 2, 2025
3362542
bugs in csv writing fixed
bkarimii Sep 2, 2025
d91dc1a
bugs in writeAnimalTraitsToCSV fixed
bkarimii Sep 3, 2025
9fde645
bug fixed in Goat
bkarimii Sep 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion project1/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,5 @@ out/
.vscode/

chart.png
data.csv
data.csv
*.csv
143 changes: 137 additions & 6 deletions project1/src/main/java/uk/co/cpsd/javaproject1/Animal.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package uk.co.cpsd.javaproject1;

import java.awt.Color;
import java.util.HashMap;
import java.util.List;
import java.awt.Point;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

public abstract class Animal {
Expand All @@ -14,6 +17,20 @@ public abstract class Animal {
protected int lastReproductionTick = -1;
private int age = 0;
protected Point position;
protected int generation; // define generation of the animal ,
protected double speed; // common traits among all Species
protected double reproductionPower; // common traits among all Species
protected int lastMoveTick=-1;

protected boolean isPregnant = false;
protected int pregnancyStartTick = -1;
protected int pregnancyDurationTicks = 0;
protected Animal pregnancyPartner;

protected DNA dna=new DNA();

Random random = new Random();


private final Gender gender;

Expand All @@ -36,6 +53,33 @@ public Animal(int x, int y, int energyLevel) {
this.energyLevel = energyLevel;
this.gender = Math.random() < .5 ? Gender.MALE : Gender.FEMALE;
this.animalId = idCounter.getAndIncrement();

// Initialize DNA traits if not already present
if (!dna.hasTraits("reproductionPower")) {
double reproductionPower = 5.0 + random.nextDouble() * 2; // Random 5-7
reproductionPower = Math.round(reproductionPower * 100.0) / 100.0; // Round to 2 decimals
dna.setTrait("reproductionPower", reproductionPower);
}

if (!dna.hasTraits("speed")) {
double speed = 5.0 + random.nextDouble() * 2; // Random 5-7
speed = Math.round(speed * 100.0) / 100.0; // Round to 2 decimals
dna.setTrait("speed", speed);
}

if (!dna.hasTraits("generation")) {
dna.setTrait("generation", 1); // Initial generation
}
if (!dna.hasTraits("animalId")) {
dna.setTrait("animalId", animalId); // store as Integer
}

if(!dna.hasTraits("parentsId")){
dna.setTrait("parentId","f0m0");
}

reproductionPower = dna.getTrait("reproductionPower", Double.class);
speed = dna.getTrait("speed", Double.class);
}

public Gender getGender() {
Expand Down Expand Up @@ -70,12 +114,14 @@ public int getEnergy() {

public abstract DecisionInfo animalDecisionMaking(World world);

public abstract int moveCooldown();

public void setPosition(Point point, int cost) {
applyMovementCost(cost);
this.position = new Point(point); // returns a copy
}

public Animal reproduceWithTwo(Animal partner, int currentTick) {
public Animal reproduceWith(Animal partner, int currentTick) {
// both animals are of the same species
if (!this.getClass().equals(partner.getClass())) {
throw new IllegalArgumentException("Animals must be of the same species to reproduce.");
Expand All @@ -85,17 +131,32 @@ public Animal reproduceWithTwo(Animal partner, int currentTick) {
this.lastReproductionTick = currentTick;
partner.lastReproductionTick = currentTick;

// Only females get pregnant
Animal female = this.gender == Gender.FEMALE ? this : partner;
Animal male = this.gender == Gender.MALE ? this : partner;

if (!female.isPregnant) {
female.isPregnant = true;
female.pregnancyStartTick = currentTick;
female.pregnancyDurationTicks = female.getPregnancyDuration();
female.pregnancyPartner = male;

// Start of preg
System.out.println("Pregnancy started for " + female.getClass().getSimpleName() +
" ID " + female.animalId + " at tick " + currentTick +
", duration: " + female.pregnancyDurationTicks + " ticks");
}

// Subtract energy based on species and gender
this.energyLevel -= getReproductionEnergyCost(this.gender);
partner.energyLevel -= getReproductionEnergyCost(partner.gender);

// Create baby
Animal baby = createBaby(this.position.x, this.position.y);
baby.energyLevel = getInitialBabyEnergy();
return null; // Baby created later in act()

return baby;
}

protected abstract int getPregnancyDuration();

public int getLastReproductionTick() {
return lastReproductionTick;
}
Expand All @@ -108,10 +169,80 @@ public boolean willMate(Animal otherAnimal, int currentTick) {

boolean bothAnimalHaveEnergy = this.isFertile(currentTick) && otherAnimal.isFertile(currentTick);
boolean isOppositeGender = this.gender != otherAnimal.gender;
boolean notPregnant = !this.isPregnant && !otherAnimal.isPregnant;
return bothAnimalHaveEnergy && isOppositeGender && notPregnant;
}

return bothAnimalHaveEnergy && isOppositeGender;
protected void handlePregnancy(World world, List<Animal> babyAnimalHolder) {

if (isPregnant && (world.getTotalTicks() - pregnancyStartTick >= pregnancyDurationTicks)) {
// Create baby
Animal baby = createBaby(position.x, position.y);
baby.energyLevel = getInitialBabyEnergy();

// Initialize baby DNA
// Map<String, Double> babyDNA = new HashMap<>();
DNA babyDNA=new DNA();
for (String key : dna.getTraitsName()) {

if (key.equals("generation") || key.equals("animalId") || key.equals("parentsId")) {
continue;
}

Object parent1Value = dna.getTrait(key, Object.class); // Mother's value
Object parent2Value = pregnancyPartner != null ?
pregnancyPartner.dna.getTrait(key, Object.class) : parent1Value;

if (parent1Value instanceof Number && parent2Value instanceof Number) {

double val1 = ((Number) parent1Value).doubleValue();
double val2 = ((Number) parent2Value).doubleValue();
double avgValue = (val1 + val2) / 2.0;
if (random.nextDouble() < 0.1) {
avgValue += random.nextGaussian();
avgValue = Math.max(0, Math.min(avgValue, 12));
}
avgValue = Math.round(avgValue * 100.0) / 100.0;
babyDNA.setTrait(key, avgValue);
} else {
babyDNA.setTrait(key, parent1Value);
}
}

Integer parent1Gen = dna.getTrait("generation", Integer.class);
Integer parent2Gen = pregnancyPartner != null ?
pregnancyPartner.dna.getTrait("generation", Integer.class) : parent1Gen;
babyDNA.setTrait("generation", Math.max(parent1Gen, parent2Gen) + 1);

babyDNA.setTrait("animalId", baby.animalId);

//parentsId
String parentsId = "f" + this.animalId + "m" + (pregnancyPartner != null ? pregnancyPartner.animalId : 0);
babyDNA.setTrait("parentsId", parentsId);

baby.dna = babyDNA;

// baby birth check
System.out.println("Baby " + baby.getClass().getSimpleName() + " ID " + baby.animalId +
" born to " + this.getClass().getSimpleName() + " ID " + this.animalId +
" at tick " + world.getTotalTicks() +
" at position (" + position.x + "," + position.y + ")");

// Log the baby's traits to CSV
world.writeAnimalTraitsToCSV(baby);

// Reset pregnancy
isPregnant = false;
pregnancyStartTick = -1;
pregnancyDurationTicks = 0;
pregnancyPartner = null;

// Add baby to the world
babyAnimalHolder.add(baby);
}
}


public abstract boolean isFertile(int tick);

protected abstract int getReproductionEnergyCost(Gender gender);
Expand Down
29 changes: 29 additions & 0 deletions project1/src/main/java/uk/co/cpsd/javaproject1/DNA.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package uk.co.cpsd.javaproject1;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class DNA {

private final Map<String,Object> traits=new HashMap<>();

public <T> void setTrait(String name, T value){
traits.put(name,value);
}

public <T> T getTrait(String name, Class<T> type){
Object value=traits.get(name);
if(value==null) return null;
return type.cast(value);

}

public Set<String> getTraitsName(){
return traits.keySet();
}

public boolean hasTraits(String name){
return traits.containsKey(name);
}
}
Loading