Files
2026-05-29 15:11:31 +07:00

178 lines
5.9 KiB
Lua

local ____lualib = require("lualib_bundle")
local __TS__Class = ____lualib.__TS__Class
local __TS__Delete = ____lualib.__TS__Delete
local __TS__ArrayIndexOf = ____lualib.__TS__ArrayIndexOf
local __TS__ArraySplice = ____lualib.__TS__ArraySplice
local __TS__New = ____lualib.__TS__New
local ____exports = {}
____exports.WeightedPool = __TS__Class()
local WeightedPool = ____exports.WeightedPool
WeightedPool.name = "WeightedPool"
WeightedPool.____file_path = "scripts/vscripts/lib/pool.lua"
function WeightedPool.prototype.____constructor(self, name, upperLimit, gain)
if name == nil then
name = "Безымянный пул"
end
self.data = {}
self.mappingTable = {}
self.len = 0
self.totalProportion = 0
self.virtualTotalProportion = 0
self.gain = 10000
self.name = name
self.upperLimit = upperLimit
self.gain = gain or 10000
end
function WeightedPool.prototype.add(self, object, proportion)
if proportion == nil then
proportion = 1
end
if self.mappingTable[object] then
local currentWeight = self:getWeightPrize(object)
self:remove(object)
return self:add(object, currentWeight + proportion)
end
if self.upperLimit and self.len >= self.upperLimit then
return self
end
self.totalProportion = self.totalProportion + proportion
self.virtualTotalProportion = math.floor(self.totalProportion * self.gain)
local weightPrize = {object = object, proportion = proportion, virtualProportion = proportion * self.gain}
self.mappingTable[object] = weightPrize
local ____self_data_0 = self.data
____self_data_0[#____self_data_0 + 1] = weightPrize
self.len = self.len + 1
return self
end
function WeightedPool.prototype.sub(self, object, proportion)
if self.mappingTable[object] then
local currentWeight = self:getWeightPrize(object)
self:remove(object)
self:add(object, currentWeight - proportion)
else
end
end
function WeightedPool.prototype.remove(self, object)
if not self.mappingTable[object] then
return
end
local prize = self.mappingTable[object]
__TS__Delete(self.mappingTable, object)
local index = __TS__ArrayIndexOf(self.data, prize)
if index > -1 then
__TS__ArraySplice(self.data, index, 1)
end
self.totalProportion = self.totalProportion - prize.proportion
self.virtualTotalProportion = math.floor(self.totalProportion * self.gain)
self.len = self.len - 1
end
function WeightedPool.prototype.getProbability(self, object)
local weightPrize = self.mappingTable[object]
if not weightPrize then
return {0, 0}
end
return {weightPrize.proportion / self.totalProportion, weightPrize.proportion}
end
function WeightedPool.prototype.getWeightPrize(self, object)
local weightPrize = self.mappingTable[object]
return weightPrize ~= nil and weightPrize.proportion or 0
end
function WeightedPool.prototype.setWeightPrize(self, object, proportion)
local weightPrize = self.mappingTable[object]
if not weightPrize then
return {0, 0}
end
local used = weightPrize.proportion
self.totalProportion = self.totalProportion - used
weightPrize.proportion = proportion
weightPrize.virtualProportion = proportion * self.gain
self.totalProportion = self.totalProportion + proportion
self.virtualTotalProportion = math.floor(self.totalProportion * self.gain)
return {used, proportion}
end
function WeightedPool.prototype.random(self)
if self.len == 0 then
return nil
end
local winningProbability = RandomInt(1, self.virtualTotalProportion)
for ____, prize in ipairs(self.data) do
winningProbability = winningProbability - prize.virtualProportion
if winningProbability <= 0 then
return prize.object
end
end
return nil
end
function WeightedPool.prototype.randomAndRemove(self)
if self.len == 0 then
return nil
end
local winningProbability = RandomInt(1, self.virtualTotalProportion)
for ____, prize in ipairs(self.data) do
winningProbability = winningProbability - prize.virtualProportion
if winningProbability <= 0 then
self:remove(prize.object)
return prize.object
end
end
return nil
end
function WeightedPool.prototype.clear(self)
self.len = 0
self.data = {}
self.mappingTable = {}
self.totalProportion = 0
self.virtualTotalProportion = 0
end
function WeightedPool.prototype.randomSole(self, n)
local result = {}
local temp = {}
do
local i = 0
while i < n do
local obj = self:random()
if obj ~= nil then
result[#result + 1] = obj
local weight = self:getWeightPrize(obj)
temp[#temp + 1] = {obj, weight}
self:setWeightPrize(obj, 0)
end
i = i + 1
end
end
for ____, ____value in ipairs(temp) do
local obj = ____value[1]
local weight = ____value[2]
self:setWeightPrize(obj, weight)
end
return result
end
function WeightedPool.prototype.randomCard(self, n)
local result = {}
local temp = {}
do
local i = 0
while i < n do
local obj = self:random()
if obj ~= nil then
result[#result + 1] = obj
local weight = self:getWeightPrize(obj)
temp[#temp + 1] = {obj, weight}
local newWeight = weight - 1
self:setWeightPrize(obj, newWeight >= 0 and newWeight or 0)
end
i = i + 1
end
end
for ____, ____value in ipairs(temp) do
local obj = ____value[1]
local currentWeight = self:getWeightPrize(obj)
self:setWeightPrize(obj, currentWeight + 1)
end
return result
end
_G.pool = function(____, name, upperLimit, gain)
return __TS__New(____exports.WeightedPool, name, upperLimit, gain)
end
return ____exports