Created
January 26, 2024 00:08
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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