Calculating growth rate of a population of Minecraft chickens

1.3k Views Asked by At

I have a rather strange question (for this Stack Exchange anyway). It felt too mathematical to ask elsewhere. If this is out of place here, please let me know.

A chicken in Minecraft lays eggs; the time between layings is uniformly distributed between 5 and 10 minutes in intervals of 0.05 seconds. An egg, when thrown, produces one chick with probability $\frac3{32}$ or four chicks with probability $\frac1{32}$, and is destroyed afterwards regardless. A chick matures into an egg-laying chicken in 20 minutes.

Assuming eggs are immediately thrown upon laying, how can I estimate the number of chickens after $X$ minutes starting with 1 chicken (that is at the start of its egg-laying cycle)? Chickens are immortal.

I can figure most of it out myself, but the thing that's giving me the most trouble is the last bit. I don't know how to take into account the time delay between an egg hatching and the chick growing up.

1

There are 1 best solutions below

0
On

Well, this is well above my capabilities to solve the problem analytically but I can do a nice simulation using the following code:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

public class Chicken {
    public static final int STARTING_CHICKENS = 1;
    public static final int TOTAL_MINUTES = 400;
    public static final int REPORTING_PERIOD = 5; // minutes

    public static final int LAYING_START = 5; // minutes
    public static final int LAYING_END = 10; // minutes
    public static final int MATURING_PERIOD = 20; // minutes

    public static final int TICKS_PER_SECOND = 20; // 0.05 seconds
    public static final int TICKS_PER_MINUTE = 60 * TICKS_PER_SECOND;

    public static final int LAYING_START_TICKS = LAYING_START * TICKS_PER_MINUTE;
    public static final int LAYING_END_TICKS = LAYING_END * TICKS_PER_MINUTE;
    public static final int MATURING_TICKS = MATURING_PERIOD * TICKS_PER_MINUTE;
    public static final int TOTAL_TICKS = TOTAL_MINUTES * TICKS_PER_MINUTE;
    public static final int REPORTING_TICKS = REPORTING_PERIOD * TICKS_PER_MINUTE;

    public static final double ONE_CHICK_PROBABILITY = 3D / 32D;
    public static final double FOUR_CHICKS_PROBABILITY = 1D / 32D;

    private static Random rnd = new Random();

    private int ticks;
    private int nextEggTick;

    public Chicken() {
        this.ticks = 0;
        this.nextEggTick = MATURING_TICKS;
    }

    public List<Chicken> tick() {
        ticks++;
        if(ticks == nextEggTick) {
            // update next egg time
            nextEggTick = ticks + LAYING_START_TICKS + rnd.nextInt(LAYING_END_TICKS - LAYING_START_TICKS + 1);
            // lay an egg
            double r = rnd.nextDouble();
            if (r < FOUR_CHICKS_PROBABILITY) {
                return Arrays.asList(new Chicken(), new Chicken(), new Chicken(), new Chicken());
            }
            else if (r < FOUR_CHICKS_PROBABILITY + ONE_CHICK_PROBABILITY) {
                return Arrays.asList(new Chicken());
            }
        }
        return Arrays.asList();
    }

    public static void main(String[]  args) {
        StringBuffer output = new StringBuffer("{");
        List<Chicken> chickens = new ArrayList<>();
        for(int i = 0; i < STARTING_CHICKENS; i++) {
            chickens.add(new Chicken());
        }
        int ticks = 0;
        while(ticks <= TOTAL_TICKS) {
            if(ticks % REPORTING_TICKS == 0) {
                report(output, ticks, chickens);
            }
            ticks++;
            List<Chicken> newChickens = new ArrayList<>();
            for(Chicken chicken: chickens) {
                newChickens.addAll(chicken.tick());
            }
            chickens.addAll(newChickens);
        }
        output.append("}");
        System.out.println(output.toString());
    }

    private static void report(StringBuffer output, int ticks, List<Chicken> chickens) {
        int minutes = ticks / TICKS_PER_MINUTE;
        String msg = String.format("{%d, %d}", minutes, chickens.size());
        System.out.println(msg);
        if(output.length() > 1) {
            output.append(", ");
        }
        output.append(msg);
    }
}

I did run 10 simulations and got exponential growth of chickens:

enter image description here

...which becomes perfectly clear when you use logarithmic scale:

enter image description here

Actually, it looks like the process "struggles" in the beginning. With a small number number of chickens it might take considerable time for population to reach, say, 10 chickens. After that, the population is big enough and reproduction starts to go smoothly, always at the same exponential rate.

It can be stated empirically that, for a big enough number of minutes $X$, the number of chickens $Y$ changes according to:

$$\ln Y=\ln (\text{const}) + 0.021 X$$

$$Y = \text{const}\cdot e^{0.021 X}$$