using Statistics
using CairoMakie
CairoMakie.activate!(type = "svg")Horse Breeding Discrepancies
Package Importing
Horses
According to all the available guides and wikis I am able to find online (Horse - Minecraft Wiki, Tutorial: Horses - Minecraft Wiki, Horse - Minecraft Fandom Wiki, Tutorial: Horse - Minecraft Fandom Wiki, Foal Stat Predictor to name a few) horse offspring should acquire the traits of their parents with some random chance thrown in. I take this to mean that the average stat of many offspring of two parents should equal the average of the stat for those two parents. This didn’t seem to be the case so I collected some statistics. For the data below, the same two horses are used as parents for every offspring. The parent horses have 29HP and 30HP. I measure HP by hitting the horse with an open hand (dealing 1HP damage) until I see the HUD mount HP indicator go down and then I can say for certain how much HP the horse had originally. Measurements here are in HP (0.5 hearts). I feed the two parents golden carrots, wait for the offspring to grow up naturally, check its HP and record the value. I have repeated this process many times to gather statistics and plot them below.
childHealth=[17, 21, 26, 24, 15, 19, 17, 25, 26, 17, 17, 25, 23, 25, 17, 26, 26, 23, 24, 20, 27, 20, 22, 30, 17, 26, 22, 28, 25, 22, 16, 23, 19, 21, 21, 16, 29, 21, 22, 20, 28, 16, 18, 20, 18, 15, 23, 16, 28, 17, 25, 25, 30]
mu=mean(childHealth)
sem=std(childHealth)/sqrt(length(childHealth))
parentA=29
parentB=30
fig=Figure()
ax=Axis(fig[1,1], title="Measured Horse Offspring Health", xlabel="Offspring HP", ylabel="Counts")
hist!(ax, childHealth, bins=14.5:1.0:30.5)
vlines!(ax, [parentA, parentB, mu], color=[:red, :blue, :green])
band!(ax, range(0,8), mu-sem, mu+sem, color=:green, alpha=0.2, direction=:y)
text!(ax, [(parentA-0.2, 5), (parentB-0.2, 4.5), (mu-0.2, 5)], text=["Parent A", "Parent B", "Offspring Average\n+/- 1 standard error"], color=[:red, :blue, :green], align=(:right, :top))
save("horseHist.svg", fig)
figThe histogram shows that the average HP of the 53 offspring is 21.9 \(\pm\) 0.6 which is nowhere near the average parents HP of 29.5.
Donkeys
I have also performed these measurements on donkeys. In this case I am breeding two donkeys with 30 HP but the rest of the details are the same as for the horses described above.
childHealth=[28, 29, 21, 18, 19, 20, 24, 25, 28, 29, 27, 25, 17, 22, 17, 17, 21, 15, 17, 17, 17, 18, 25, 15, 19, 19, 28, 29, 19, 24, 28, 29, 19, 22, 15, 23, 23, 22, 29]
mu=mean(childHealth)
sem=std(childHealth)/sqrt(length(childHealth))
parentA=30
parentB=30
fig=Figure()
ax=Axis(fig[1,1], title="Measured Donkey Offspring HP", xlabel="Offspring HP", ylabel="Counts")
hist!(ax, childHealth, bins=14.5:1.0:30.5)
vlines!(ax, [parentA, parentB, mu], color=[:blue, :blue, :green])
band!(ax, range(0,6), mu-sem, mu+sem, color=:green, alpha=0.2, direction=:y)
text!(ax, [(parentA-0.2, 6), (parentB-0.2, 5.5), (mu-0.2, 6)], text=["Parent A", "Parent B", "Offspring Average\n+/- 1 standard error"], color=[:blue, :blue, :green], align=(:right, :top))
save("donkeyHist.svg", fig)
figThe histogram shows that the average HP of the 39 offspring is 22.0 \(\pm\) 0.7 which is nowhere near the average parents HP of 30.
Simulated Breeding (expected results)
Here, I have simulated what the common thinking is for how horse breeding works in the game (see the links at the top). To walk through it at a high level, I’m using the following equation to compute the offspring HP based on the parents’ HP, \(A\) and \(B\), three random numbers drawn from a uniform distribution with bounds (0,1), \(\phi_i\), and the maximum (\(H_\textrm{max}=30\)) and minimum (\(H_\textrm{min}=15\)) of the possible range of horse HP. \[ \begin{aligned} \textrm{Offspring HP} &= \frac{A+B}{2}+\left(\left|A-B\,\right| +0.3\left(H_\textrm{max}-H_\textrm{min}\right)\right)\left(\frac{\phi_1 +\phi_2 + \phi_3}{3} - \frac{1}{2}\right)\\ &= \frac{A+B}{2}+\left(\left|A-B\,\right| +0.3\left(H_\textrm{max}-H_\textrm{min}\right)\right)R \end{aligned} \] The random factor, \(R\), at the end of the equation is bounded between (-0.5, 0.5). It can take the value -0.5 if all \(\phi_i=0\) and +0.5 if all \(\phi_i=1\) and any other combination results in a value in this range with a bias toward zero. From this equation it is easy to see that the mean of the offspring HP is equal to the mean of the parents’ HP \((A+B)/2\) since the average value of \(R\) is zero: \[ \begin{aligned} \textrm{Mean Offspring HP} &= \frac{n(A+B)}{2n}+\left(\left|A-B\,\right| +0.3\left(H_\textrm{max}-H_\textrm{min}\right)\right)*0\\ &= \frac{A+B}{2} \end{aligned} \] But to note, this is not true if near the edges of the range, as discussed more below. Further, using the fact that \(R\in(-0.5,0.5)\) we can compute the maximum and minimum possible offspring HP using the values we have for our parents of 29HP and 30HP: \[ \begin{aligned} \textrm{Min Offspring HP} &= \frac{A+B}{2}+\left(\left|A-B\,\right| +0.3\left(H_\textrm{max}-H_\textrm{min}\right)\right)R\\ &= \frac{29+30}{2}+\left(|29-30|+0.3(30-15)\right)(-0.5)\\ &= 29.5 + (1+4.5)(-0.5)\\ &= 29.5 - 2.75\\ &= 26.75 \rightarrow 27 \end{aligned} \] And assuming rounding to the nearest integer HP, this becomes 27. \[ \begin{aligned} \textrm{Max Offspring HP} &= \frac{A+B}{2}+\left(\left|A-B\,\right| +0.3\left(H_\textrm{max}-H_\textrm{min}\right)\right)R\\ &= \frac{29+30}{2}+\left(|29-30|+0.3(30-15)\right)(0.5)\\ &= 29.5 + (1+4.5)(0.5)\\ &= 29.5 + 2.75\\ &= 32.25 \rightarrow 28 \end{aligned} \] This max HP is above the maximum horse HP value of 30. I’m also operating on the assumption that values above 30 are “reflected” back. For example, this 32.25 value becomes 30-2.25 = 27.75, which rounds to 28. To formulate this mathematically I define if \(\textrm{HP}>H_\textrm{max}\) then \(\textrm{HP} \rightarrow 2H_\textrm{max}-\textrm{HP}\) and if \(\textrm{HP}<H_\textrm{min}\) then \(\textrm{HP}\rightarrow 2H_\textrm{min}-\textrm{HP}\). This also implies that when near enough to the edges of the range such that values are reflected, the fact that the average offspring HP should be the same as the average of the parents is no longer true.
parentA=29
parentB=30
c=[]
for i in 1:100000
r = (rand()+rand()+rand())/3.0 - 0.5
p = r*(abs(parentA-parentB)+0.3*15.0) + mean([parentA, parentB])
if p > 30.0
p = 60.0 - p
elseif p < 15.0
p = 30.0 - p
end
push!(c, p)
end
mu = mean(c)
sem = std(c)/sqrt(length(c))
fig=Figure()
ax=Axis(fig[1,1], title="Expected Offspring Health", xlabel="Offspring HP", ylabel="Probability")
hist!(ax, c, normalization=:probability, bins=25.5:1.0:30.5)
vlines!(ax, [parentA, parentB, mu], color=[:red, :blue, :green])
band!(ax, 0.0:0.01:0.2, mu-sem, mu+sem, color=:green, alpha=0.2, direction=:y)
text!(ax, [(parentA-0.1, 0.6), (parentB-0.1, 0.6)], text=["Parent A", "Parent B"], color=[:red, :blue], align=(:right, :top))
text!(ax, [(mu+0.05, 0.55)], text = ["Offspring Average\n+/- 1 standard error"], color=[:green], align=(:left,:top))
save("expectedHist.svg", fig)
fig