Arbitrary system
I came up with a system for handling genders. In this system, a female is FF, a male is MM, and a hermaphrodite is FM. So if a female and a male breed, they have only hermaphroditic offspring. If a hermaphrodite breeds with either other sex, there's a 50% chance of a hermaphrodite and a 50% chance that the child is the same gender as the other partner. If two hermaphrodites breed, they have a 50% chance of a hermaphrodite and 25% each for the other genders.
+---+----+----+ +---+----+----+ +---+----+----+ +---+----+----+
| | F | F | | | F | F | | | F | M | | | F | M |
+---+----+----+ +---+----+----+ +---+----+----+ +---+----+----+
| M | FM | FM | | F | FF | FF | | M | FM | MM | | F | FF | FM |
+---+----+----+ +---+----+----+ +---+----+----+ +---+----+----+
| M | FM | FM | | M | FM | FM | | M | FM | MM | | M | FM | MM |
+---+----+----+ +---+----+----+ +---+----+----+ +---+----+----+
I ran some simulations (code and assumptions at the bottom). I found a slight preference for hermaphroditic offspring overall but a stable one. So perhaps 56-57% hermaphrodite and evenly distributed between the other two. Note that it is possible to favor males over females or vice versa. For example, a rule that hermaphrodites and females only breed with males (possibly allowing males with multiple spouses) would eliminate females and keep females eliminated so long as it was followed.
This was based purely on those rules. If you have different rules, then you're going to get different results. It might be better to approach the problem from the other direction. How would you like to split the genders and why? Some splits may not have an easy explanation.
Alternatives
I read a book a while ago where gender was determined by the gender ratio around the child. So all children were neuters. The move to adulthood occurred when the child would develop a gender. A child surrounded by females would become male. A child surrounded by males would become female. You could extend that to include hermaphrodites (surrounded by equal numbers of males and females). And you could provide arbitrary rules for the development of children surrounded by hermaphrodites. That society could choose its gender ratio if it wanted.
We often act like males and females are perfectly evenly divided in humans. But actually Y sperm are more likely to form. This is partially offset as Y sperm are less likely to succeed to fertilization. But overall, there are more boy babies than girl babies. Boys/men are also more fragile, dying in accidents more often. With modern medicine, women seldom die due to pregnancy. So by retirement age, there are more women than men.
Anyway, you can use similar mechanisms to alter ratios in your humanoids. Perhaps there is some birth defect that is common in one gender or another that leads to miscarriage. Perhaps hermaphrodites produce less sperm. Perhaps the genetics is more complicated.
Simulation code
GenderSimulator.java
import java.security.SecureRandom;
import java.util.EnumMap;
import java.util.Map;
import java.util.Random;
public class GenderSimulator {
public enum Gender {
FEMALE, HERMAPHRODITE, MALE;
public Gender opposite() {
switch (this) {
case FEMALE:
return MALE;
case MALE:
return FEMALE;
default:
return null;
}
}
}
public static class Generation {
Map<Gender, Integer> genderCounts = new EnumMap<Gender, Integer>(Gender.class);
public Generation() {
this(0, 0, 0);
}
public Generation(int femaleCount, int hermaphroditeCount, int maleCount) {
genderCounts.put(Gender.FEMALE, femaleCount);
genderCounts.put(Gender.HERMAPHRODITE, hermaphroditeCount);
genderCounts.put(Gender.MALE, maleCount);
}
public Generation generateNext() {
Generation generation = new Generation();
generateRandomCouples(generation);
generateFemaleMaleCouples(generation);
generateCouples(generation, Gender.FEMALE);
generateCouples(generation, Gender.MALE);
generateFromHermaphrodites(generation);
return generation;
}
public int size() {
int sum = 0;
for (int count : genderCounts.values()) {
sum += count;
}
return sum;
}
public int count(Gender gender) {
Integer count = genderCounts.get(gender);
return (count == null) ? 0 : count;
}
private void add(Gender gender, int amount) {
int count = count(gender);
genderCounts.put(gender, count + amount);
}
private Gender chooseGenderChildOfHermaphrodites() {
int choice = RANDOM.nextInt(4);
if (choice == 0) {
return Gender.FEMALE;
} else if (choice == 3) {
return Gender.MALE;
} else {
return Gender.HERMAPHRODITE;
}
}
private Gender chooseGenderChild(Gender gender) {
return RANDOM.nextBoolean() ? Gender.HERMAPHRODITE : gender;
}
private Gender chooseGenderParent() {
int choice = RANDOM.nextInt(count(Gender.HERMAPHRODITE) + count(Gender.MALE) + count(Gender.FEMALE));
if (choice < count(Gender.HERMAPHRODITE)) {
return Gender.HERMAPHRODITE;
} else if (choice < count(Gender.HERMAPHRODITE) + count(Gender.MALE)) {
return Gender.MALE;
}
return Gender.FEMALE;
}
private boolean hasHermaphroditeParent(Gender gender) {
return RANDOM.nextInt(count(Gender.HERMAPHRODITE) + count(gender)) < count(Gender.HERMAPHRODITE);
}
private void breedWith(Generation generation, Gender gender) {
add(gender, -1);
if (hasHermaphroditeParent(gender.opposite())) {
add(Gender.HERMAPHRODITE, -1);
generation.add(chooseGenderChild(gender), 1);
generation.add(chooseGenderChild(gender), 1);
} else {
add(gender.opposite(), -1);
generation.add(Gender.HERMAPHRODITE, 2);
}
}
private void generateFemaleMaleCouples(Generation generation) {
int maleCount = count(Gender.MALE);
int femaleCount = count(Gender.FEMALE);
int count = Math.min(maleCount, femaleCount);
genderCounts.put(Gender.MALE, maleCount - count);
genderCounts.put(Gender.FEMALE, femaleCount - count);
generation.add(Gender.HERMAPHRODITE, 2 * count);
}
private void generateRandomCouples(Generation generation) {
while (count(Gender.HERMAPHRODITE) - 1 > Math.abs(count(Gender.MALE) - count(Gender.FEMALE))
&& count(Gender.FEMALE) > 0 && count(Gender.MALE) > 0) {
Gender parent = chooseGenderParent();
if (parent == Gender.HERMAPHRODITE) {
add(Gender.HERMAPHRODITE, -1);
Gender other = chooseGenderParent();
if (other == Gender.HERMAPHRODITE) {
add(Gender.HERMAPHRODITE, -1);
generation.add(generation.chooseGenderChildOfHermaphrodites(), 1);
generation.add(generation.chooseGenderChildOfHermaphrodites(), 1);
} else {
add(other, -1);
generation.add(chooseGenderChild(other), 1);
generation.add(chooseGenderChild(other), 1);
}
} else {
breedWith(generation, parent);
}
}
}
private void generateCouples(Generation generation, Gender gender) {
while (count(gender) > 0 && count(Gender.HERMAPHRODITE) > 0) {
add(gender, -1);
add(Gender.HERMAPHRODITE, -1);
generation.add(chooseGenderChild(gender), 1);
generation.add(chooseGenderChild(gender), 1);
}
}
private void generateFromHermaphrodites(Generation generation) {
while (count(Gender.HERMAPHRODITE) > 1) {
add(Gender.HERMAPHRODITE, -2);
generation.add(generation.chooseGenderChildOfHermaphrodites(), 1);
generation.add(generation.chooseGenderChildOfHermaphrodites(), 1);
}
}
public String toString() {
return toString("-");
}
public String toString(String delimiter) {
StringBuilder builder = new StringBuilder();
builder.append(genderCounts.get(Gender.FEMALE));
builder.append(delimiter);
builder.append(genderCounts.get(Gender.HERMAPHRODITE));
builder.append(delimiter);
builder.append(genderCounts.get(Gender.MALE));
return builder.toString();
}
}
public final static Random RANDOM = new SecureRandom();
public static void main(String[] args) {
Generation generation = new Generation(2150, 5700, 2150);
System.out.println(generation);
int size = generation.size();
while (true) {
generation = generation.generateNext();
System.out.println(generation);
if (size != generation.size()) {
break;
}
size = generation.size();
}
}
}
Assumptions:
- Breeding is monogamous (if you breed with someone, all your children are with that someone);
- Any compatible and available partner is equally likely (hermaphrodites are neither preferred nor avoided as partners relative to the other genders);
- No male/male or female/female relationships, as those wouldn't produce offspring;
- Every couple has two children (stable population);
- Everyone breeds with someone (also needed for a stable population).
Note that this code is not particularly flexible. You can't swap breeding strategies in and out. That's hard coded. Changing the first generation involves modifying code. This is mainly designed to test my initial hypothesis that hermaphrodites would make up 50% of the population. That does not seem to be true. The hermaphrodite population stabilizes around 56-57% when everything is random.
The other genders are less stable, fluctuating in a much wider band.
I used interior classes because it was easier for me to do this in just one file. I used SecureRandom
because I didn't seem to need more efficiency, and I wanted to be sure that my results weren't being tainted by too much pseudo in my random. I didn't notice any difference between the two, so you could switch back if you wanted.