Módulo:Drop rate calculator
Documentação do módulo
Esta documentação é transcluída de Predefinição:Sem documentação/doc. [editar] [atualizar]
Este módulo não possui nenhuma documentação. Por favor, considere adicionar uma documentação em Módulo:Drop rate calculator/doc. [editar]
Módulo:Drop rate calculator requer Módulo:Chart data.
Módulo:Drop rate calculator requer Módulo:Enum.
Módulo:Drop rate calculator requer Módulo:Yesno.
-- <nowiki>
local yesno = require( 'Módulo:Yesno' )
local chart = require( 'Módulo:Chart data' )
local enum = require( 'Módulo:Enum' )
local min = math.min
local max = math.max
local log = math.log
local floor = math.floor
local ceil = math.ceil
local abs = math.abs
local p = {}
local function formatNum( num )
local x = num
if num > 99 then
x = 100 - num
end
local mag = min( max( -floor( math.log10( x ) ) + 1, 1 ), 12 )
return (string.format( '%.' .. mag .. 'f', num ):gsub( '0+$', '' ):gsub( '%.$', '.0' ))
end
local function interPol( x, x1, y1, x2, y2 )
return (x - x1) * (y2 - y1) / (x2 - x1) + y1
end
local function getKillCountProb( kills, arr )
local i = enum.find_index( arr, function(item) return item.x > kills end )
return interPol( kills, arr[i-1].x, arr[i-1].y, arr[i].x, arr[i].y )
end
-- sum(r^n, n=0..t-1)
local function powerSeries1( r, t )
return (r^t - 1) / (r - 1)
end
-- sum(n*r^n, n=0..t-1)
local function powerSeries2( r, t )
return ((t - 1) * r^(t + 1) - t * r^t + r) / (r - 1)^2
end
local function getKillCountForGivenChance( chance, droprate, threshold )
chance = chance / 100
if threshold then
local c = 0
local m = 1
local kc = 0
while true do
local newC = 1 - (1 - c) * (1 - m * droprate)^threshold
if newC >= chance then
kc = kc + log( (1 - chance) / (1 - c) ) / log( (1 - m * droprate) )
return ceil( kc )
else
kc = kc + threshold
c = newC
end
m = m + 1
end
else
return ceil( log( 1 - chance ) / log( 1 - droprate ) )
end
end
function p.main( frame )
return p._main( frame:getParent().args )
end
function p._main( args )
local kills = tonumber( args.kills ) or 1
local droprate = 1 / (tonumber( args.droprate ) or 1)
local hasThreshold = yesno( args.hasThreshold )
local threshold = tonumber( args.threshold ) or 1000
local probArr = { {x=0, y=0} }
local probArrNoThreshold = { {x=0, y=0} }
local arrLen = 1
local stepSize = max( floor( kills / 250 ), 1 )
local killCountProb = 0
for i = stepSize, 2 * kills, stepSize do
local probNoThreshold = probArrNoThreshold[arrLen].y
probNoThreshold = 100 - (100 - probNoThreshold) * (1 - droprate)^stepSize
probArrNoThreshold[arrLen + 1] = { x=i, y=probNoThreshold }
if hasThreshold then
local probThreshold = probArr[arrLen].y
local interStep = 0
local _i = i - stepSize
repeat
interStep = min( i - _i, threshold )
_i = _i + interStep
local multiplier = ceil( _i / threshold )
if threshold > 1 and _i > threshold and (_i - 1) % threshold < interStep then -- the multiplier changed in between i and i + stepSize
local subStep = ((_i - 1) % threshold) + 1
probThreshold = 100 - (100 - probThreshold) * (1 - min( (multiplier - 1) * droprate, 1 ))^(interStep - subStep)
probThreshold = 100 - (100 - probThreshold) * (1 - min( multiplier * droprate, 1 ))^subStep
else
probThreshold = 100 - (100 - probThreshold) * (1 - min( multiplier * droprate, 1 ))^interStep
end
until _i >= i
probArr[arrLen + 1] = { x=i, y=probThreshold }
end
arrLen = arrLen + 1
end
if hasThreshold then
killCountProb = getKillCountProb( kills, probArr )
else
killCountProb = getKillCountProb( kills, probArrNoThreshold )
end
local averageKC = 0
if hasThreshold then
-- Calculate the weigthed average over the probabilty distribution from 0 to inf (we can stop sooner as values become insignificant small)
-- => Calculate the sum of the prodcuct of each kill count value with the chance to obtain it at that kill count
--
-- l = start of each threshold bin. If threshold = 1000 then l = 1, 1001, 2001, ...
-- c = combined succes and fail chance from previous threshold bins. In bin one c = droprate, bin two c = 2 * droprate * (1 - droprate)^threshold,
-- bin three c = 3 * droprate * (1 - droprate)^threshold * (1 - 2 * droprate)^threshold, ...
-- r = (1 - multiplier * droprate)
--
-- Each threshold bin can then be written as
-- l*c + (l+1)*c*r + (l+2)*c*r^2 + (l+3)*c*r^3 + ... + (l + threshold - 1)*c*r^(threshold - 1)
-- => c*(l + l*r + r + l*r^2 + 2*r^2 + l*r^3 + 3*r^3 + ...)
-- => c*(l*(1 + r + r^2 + r^3 + ...) + r + 2r^2 + 3r^3 + ...)
-- (1 + r + r^2 + r^3 + ...) and (r + 2r^2 + 3r^3 + ...) are powerseries
local c = droprate
local m = 1
local prev = 0
local initialChange = 0
repeat
prev = averageKC
local r = 1 - min( m * droprate, 1 )
local l = (m - 1) * threshold + 1
averageKC = averageKC + c * (l * powerSeries1( r, threshold ) + powerSeries2( r, threshold ))
c = c * r^threshold * (1 + 1 / m)
m = m + 1
if initialChange == 0 then
initialChange = abs( prev - averageKC )
end
until abs( prev - averageKC ) < min( initialChange / 1000, 0.01 )
else
averageKC = 1 / droprate
end
averageKC = floor( averageKC + 0.5 )
local plot = chart.newChart{ type='scatter' }
:setTitle( 'Chance de pelo menos um objeto largado vs contagem de mortes' )
:setDimensions( '40vw', '40vh', '400px', '400px', true )
:setXLabel( 'Número de abates' )
:setYLabel( 'Chance de pelo menos um objeto largado' )
:showLegend( false )
plot:newDataSet{
data = probArrNoThreshold,
pointRadius = 0,
label = 'Sem limite'
}
plot:newDataSet{
data = { {x=0, y=killCountProb}, {x=kills, y=killCountProb}, {x=kills, y=0} },
pointRadius = 0,
borderDash = {10, 10},
borderWidth = 1,
lineTension = 0,
label = '- - -'
}
if hasThreshold then
plot:newDataSet{
data = probArr,
pointRadius = 0,
label = 'Sem limite',
}
plot:showLegend( true )
end
local dropRateAtKillCount = min( droprate * (hasThreshold and ceil( kills / threshold ) or 1), 1 )
return string.format( 'Taxa de obtenção de objeto largado em %d abates: 1/%s ou %s%% <br> Chance de obter objeto largado em %d abates: %s%%' ..
string.rep( '\n* %s em %d abates', 3 ) .. '\nMédia de abates %d%s',
kills,
floor( (1 / dropRateAtKillCount) + 0.5 ),
formatNum( dropRateAtKillCount * 100 ),
kills,
formatNum( killCountProb ),
'50%',
getKillCountForGivenChance( 50, droprate, hasThreshold and threshold ),
'90%',
getKillCountForGivenChance( 90, droprate, hasThreshold and threshold ),
'99%',
getKillCountForGivenChance( 99, droprate, hasThreshold and threshold ),
averageKC,
tostring( plot )
)
end
return p
-- </nowiki>