Module:Dry calc
Jump to navigation
Jump to search
Module documentation
This documentation is transcluded from Template:No documentation/doc. [edit] [history] [purge]
This module does not have any documentation. Please consider adding documentation at Module:Dry calc/doc. [edit]
Module:Dry calc's function main is invoked by Calculator:Dry calc.
local p = {}
function expr(x)
x = tostring(x)
x = x:gsub(",", ".")
local expr_good, expr_val = pcall(mw.ext.ParserFunctions.expr, x)
if expr_good then
return tonumber(expr_val)
end
return nil
end
function flavourText(x, obtained)
local flavourTexts = {
{ -1, 1, "You are some sort of sentient water being you're so not-dry. How'd you even do this?" },
{ 1, 10, "You're a higher % water than a watermelon.", "Or you would be if you had gotten any drops. But you didn't." },
{ 10, 20, "Only ironmen can be this lucky.", "But you got no drops, so I guess you're not an ironman." },
{ 20, 30, "🥄 Spooned 🥄", "j/k you got no drops" },
{ 30, 40, "Your friends will be jealous.", "...If you got any drops." },
{ 40, 49, "You're quite the lucker aren't you.", "Or not, since you got no drops." },
{ 49, 51, "A perfect mix of dry and undry, as all things should be." },
{ 51, 61, 'Nothing interesting happens.', "Not even any drops." },
{ 61, 65, "An unenlightened being would say 'but 1/x over x kills means I should get it', but you know better now." },
{ 65, 73, 'Nothing interesting happens.', "Not even any drops." },
{ 73, 74, "😂😂😂" },
{ 74, 85, "oof" },
{ 85, 90, "A national emergency has been declared in your drop log." },
{ 90, 95, "Right, time to post on reddit." },
{ 95, 99, "You after being this dry: [[File:Skeleton.png|80x80px]]" },
{ 99, 99.5, "You are so dry you have collapsed into the dry singularity. The dryularity, if you will." },
{ 99.5, 99.9, "The vacuum of space has more activity than your drop log." },
{ 99.9, 99.99, "Wow that's so rare! Seems like it's bugged. We tweeted @JagexAsh for you, we're sure he'll get to the bottom of it in the next 24 hours." },
{ 99.99, 1000, "Did you forget to talk to [[Oziach]]?" }
}
for i, v in ipairs(flavourTexts) do
if x >= v[1] and x < v[2] then
if obtained == 0 and v[4] then
return v[3]..' '..v[4]
end
return v[3]
end
end
return ''
end
function p.main(frame)
local args = frame.args
return p.calc(args.chance, args.kills, args.dropped)
end
function p.binomDist(p,n,k)
-- calculates P(B<k) and P(B=k) for B binomially distributed with probability p and n tries
-- uses log to prevent overflow/underflow issues
local logPNot = math.log(1.0-p)
local logPDiff = math.log(p)-logPNot
local logPX = n*logPNot -- start at 0 drops in n kc
local pCumulative = 0.0
for x=1,k
do
pCumulative = pCumulative + math.exp(logPX)
logPX = logPX + math.log(n-x+1.0) - math.log(x) + logPDiff
end
return pCumulative, math.exp(logPX)
end
function p.calc(chanceTxt, kc, obtained)
local chance = expr(chanceTxt)
if not chance then
return 'Looks like there was an error with your input chance, try typing it in again'
else
if chance > 1 then
chance = 1 / chance
chanceTxt = string.format("1/%s", chanceTxt)
elseif chance <= 0 then
return "You put your chance at 0 or negative, how you gonna get that drop?"
end
end
kc = tonumber(kc)
if not kc or kc == 0 then
return "You ain't killed anything you crazy fool"
end
obtained = tonumber(obtained) or 0
if kc < obtained then
return 'More items dropped than things killed? how?'
end
-- calculate P(D<obtained), P(D=obtained) and P(D>obtained) for D Binominally-distributed(kc,chance)
local pLessThanObtained = 0.0
local pExactlyObtained = 0.0
local pMoreThanObtained = 0.0
if obtained < kc/2
then
pLessThanObtained, pExactlyObtained = p.binomDist(chance, kc, obtained)
pMoreThanObtained = 1.0 - pLessThanObtained - pExactlyObtained
else
pMoreThanObtained, pExactlyObtained = p.binomDist(1.0-chance, kc, kc-obtained)
pLessThanObtained = 1.0 - pMoreThanObtained - pExactlyObtained
end
local flavour = flavourText(pMoreThanObtained * 100, obtained)
local introText = string.format("You killed %s monsters for an item with a %s (%.6f%%) drop chance. You had a:\n",
kc, chanceTxt, 100 * chance)
local probabilitiesText = string.format("* %.8f%% chance of getting exactly %s drops,\n", 100*pExactlyObtained, obtained)
if obtained > 0
then
probabilitiesText = probabilitiesText .. string.format("* %.8f%% chance of getting less than %s drops,\n", 100*pLessThanObtained, obtained)
end
if obtained < kc
then
probabilitiesText = probabilitiesText .. string.format("* %.8f%% chance of getting more than %s drops,\n", 100*pMoreThanObtained, obtained)
end
return introText .. probabilitiesText .. flavour
end
return p