-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBreeding.java
More file actions
155 lines (136 loc) · 6.06 KB
/
Breeding.java
File metadata and controls
155 lines (136 loc) · 6.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import java.util.List;
import java.util.ArrayList;
import java.util.Random;
/**
* Breeding control and gene mutation.
*
* @author Kexin Wang
* @time 2025.02.21
* @version 1.0
*/
public class Breeding {
private static final Random rand = new Random();
/** avoiding reduplicationclear */
private static List<Animal> alreadyBred = new ArrayList<>();
/**
* clear breeding list before each step
*/
public static void clearBreedingList() {
alreadyBred.clear();
}
/**
* Check whether or not this predator is to give birth at this step.
* New births will be made into free adjacent locations.
* @param newPredators A list to return newly born predators.
*/
public static void giveBirth(Animal animal, List<Animal> newAnimals) {
// New preys are born into adjacent locations.
// Get a list of adjacent free locations.
Field field = animal.getField();
List<Location> free = field.getFreeAdjacentLocations(animal.getLocation());
if (canBreed(animal, newAnimals) && free.size() > 0) {
canBreed(animal, newAnimals);
}
}
/**
* A animal can breed if it has reached the breeding age and find a valid mate.
* @return true if the animal can breed, false otherwise.
*/
private static boolean canBreed(Animal animal, List<Animal> newAnimals) {
if (animal.getAge() < animal.getBreedingAge() || alreadyBred.contains(animal)) {
return false;
}
List<Animal> candidates = new ArrayList<>();
List<Location> adjacent = animal.getField().adjacentLocations(animal.getLocation());
// find valid mates in adjacent locations
for (Location loc : adjacent) {
Animal neighbor = animal.getField().getObjectAt(loc);
if (neighbor != null
&& neighbor.getType() == animal.getType()
&& neighbor.getGender() != animal.getGender()
&& neighbor.getAge() >= neighbor.getBreedingAge()
&& !alreadyBred.contains(neighbor)) {
candidates.add(neighbor);
}
}
// try to breed until success once or fail all
for (Animal mate : candidates) {
if (rand.nextDouble() <= animal.getBreedingProbability()) {
mateWith(animal, mate, newAnimals);
alreadyBred.add(animal);
alreadyBred.add(mate);
return true;
}
}
return false;
}
private static void mateWith(Animal animal1, Animal animal2, List<Animal> newAnimals) {
int litterSize = rand.nextInt(animal1.getLitterSize()) + 1;
for (int i = 0; i < litterSize; i++) {
Location loc = animal1.getField().getFreeAdjacentLocation(animal1.getLocation());
if (loc == null) return;
String childGene = combineGenes(animal1.getGene(), animal2.getGene()); // generate child gene
Animal young;
if (animal1 instanceof Predator) {
young = new Predator(animal1.getField(), loc, animal1.getColor(), animal1.getType(), false);
} else {
young = new Prey(animal1.getField(), loc, animal1.getColor(), animal1.getType(), false);
}
young.setGene(childGene); // give child gene
newAnimals.add(young);
// print new borned animal and their genes
// System.out.println("New " + animal1.getType() + " born! Gene: " + childGene);
}
}
private static String combineGenes(String gene1, String gene2) {
if (gene1.length() != 14 || gene2.length() != 14) {
throw new IllegalArgumentException("Invalid parent genes: " + gene1 + ", " + gene2);
}
String newGene = gene1.substring(0, 7) + gene2.substring(7, 14);
if (newGene.length() != 14) {
throw new IllegalStateException("Generated invalid gene: " + newGene);
}
if (rand.nextDouble() < 0.2)
{
char[] geneArray = newGene.toCharArray();
int mutateIndex = rand.nextInt(14); // mutate random one digit
int oldValue = Character.getNumericValue(geneArray[mutateIndex]);
// 50% +1; 50% -1
int newValue = (rand.nextBoolean()) ? (oldValue + 1) % 10 : (oldValue + 9) % 10;
// ensure mutate value is valid
while (!isValidGene(mutateIndex, newGene.substring(0, mutateIndex)
+ newValue
+ newGene.substring(mutateIndex + 1, 14))) {
newValue = (rand.nextBoolean()) ? (newValue + 1) % 10 : (newValue + 9) % 10;
}
geneArray[mutateIndex] = Character.forDigit(newValue, 10);
newGene = new String(geneArray);
}
return newGene;
}
private static boolean isValidGene(int index, String gene) {
if (gene.length() != 14) {
throw new IllegalArgumentException("Invalid gene length in validation: " + gene);
}
int value;
if (index < 2) // breeding age (12-90) inclusive
{ value = Integer.parseInt(gene.substring(0, 2));
return value >= 12 && value <= 90;
} else if (index < 5) // max age (10-120) inclusive
{ value = Integer.parseInt(gene.substring(2, 5));
return value >= 10 && value <= 120;
} else if (index < 7) // breeding probability (0.00-0.50)
{ value = Integer.parseInt(gene.substring(5, 7));
return value > 0 && value < 50;
} else if (index < 9) // litter size (1-12) inclusive
{ value = Integer.parseInt(gene.substring(7, 9));
return value >= 1 && value <= 12;
} else if (index < 11) // diseable probability (0.00-0.50)
{ value = Integer.parseInt(gene.substring(9, 11));
return value > 0 && value < 50;
} else // metabolism (0.25-1.00) inclusive
{ value = value = Integer.parseInt(gene.substring(11, 14));
return value >= 25 && value <= 100;
}
}
}