Skip to content

Instantly share code, notes, and snippets.

@hibiii
Created January 26, 2024 00:08
Show Gist options
  • Save hibiii/59e98e4c85e7941ff6ec07f960a3f1eb to your computer and use it in GitHub Desktop.
Save hibiii/59e98e4c85e7941ff6ec07f960a3f1eb to your computer and use it in GitHub Desktop.
Lua script to calculate how many times you'd need to breed horses in Minecraft to get to at least a target speed
if #arg < 1 then
print 'usage: <your command> target [speed1] [speed2]'
print 'units are in m/s.'
print 'if the parents are missing, they\'re assumed to be average of 9.4m/s.'
os.exit(1)
end
--- The number of simulation runs.
local tries = tonumber(os.getenv("TRIES")) or 1000
--- Format: one value (number of breeds needed to get to target speed) per line
local export = os.getenv("HORSE_SCRIPT_EXPORT") == "YES"
local FACTOR = 42.157796
--- average: 9.4855041
local MAX = 0.3375
local MIN = 0.1125
local targetSpeed = tonumber(arg[1])
if not targetSpeed then
print 'missing target speed!'
os.exit(1)
end
targetSpeed = targetSpeed / FACTOR
if targetSpeed > MAX then
print 'target speed too fast!'
print('you\'re asking for '..(targetSpeed*FACTOR)..' m/s but the fastest is '..(MAX*FACTOR)..' m/s!!')
os.exit(1)
elseif targetSpeed < MIN then
print 'target speed too slow!'
print('you\'re asking for '..(targetSpeed*FACTOR)..' m/s but the slowest is '..(MIN*FACTOR)..' m/s!!')
os.exit(1)
end
local parent1 = tonumber(arg[2])
if not parent1 then
parent1 = 0.225
else
parent1 = parent1 / FACTOR
end
local parent2 = tonumber(arg[3])
if not parent2 then
parent2 = 0.225
else
parent2 = parent2 / FACTOR
end
if targetSpeed < parent1 and targetSpeed < parent2 then
print 'slower target speeds are not supported.'
print 'i don\'t judge you, but this tool doesn\'t support arbitrary targets.'
print 'it\'s desgned to reach the target speed or greater.'
os.exit(1)
end
local mix = function(s1, s2)
local avg = (s1 + s2) * 0.5
local extra = (MAX - MIN) * 0.15
local min = math.min(s1, s2) - extra
local max = math.max(s1, s2) + extra
local range = max - min
local i = (math.random() + math.random() + math.random()) / 3 - 0.5
local s3 = avg + range * i
if s3 > MAX then
local diff = s3 - MAX
s3 = MAX - diff
elseif s3 < MIN then
local diff = MIN - s3
s3 = MIN + diff
end
return s3
end
local runUntilTarget = function()
local i = 0
local parent1 = parent1
local parent2 = parent2
repeat
local baby = mix(parent1, parent2)
if baby > parent1 or baby > parent2 then
if parent1 > parent2 and baby > parent2 then
parent2 = baby
elseif baby > parent1 then
parent1 = baby
end
end
i = i + 1
until baby >= targetSpeed
return i
end
--- Start of Program ---
print('Parents: ['..(parent1 * FACTOR)..', '..(parent2 * FACTOR)..'], Target: >='..(targetSpeed * FACTOR)..', Tries: '..tries)
math.randomseed(os.time())
local avg = 0
local data = {}
local fastest = 1/0
local slowest = -1/0
for i = 1, tries do
-- io.write('\x1b[2K\rIterating... '..string.format("%.2f%%", (i*100) / tries)):flush()
local x = runUntilTarget()
if x > slowest then
slowest = x
end
if x < fastest then
fastest = x
end
avg = avg + (x / tries)
data[#data+1] = x
end
-- io.write('\x1b[2K\r')
table.sort(data)
local low10 = data[math.ceil(#data/10)]
local top10 = data[#data - math.ceil(#data/10)]
local top20 = data[#data - math.ceil(#data/5)]
print('Average: '..avg..' breeds')
print('Low 10%: '..low10..' breeds')
print('Top 10%: '..top10..' breeds')
print('Top 20%: '..top20..' breeds')
print('Fastest: '..fastest..' breeds')
print('Slowest: '..slowest..' breeds')
if export then
local f, err = io.open('horse_script_export.txt', 'w')
if not f or err ~= nil then
print 'could not export data!'
print(err)
os.exit(1)
end
for _, x in ipairs(data) do
local _, err = f:write(tostring(x)..'\n')
if err ~= nil then
print 'could not write the export file!'
print (err)
f:close()
os.exit(1)
end
end
f:close()
print 'Exported data!'
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment