Lang lang ist's her, meine letzte Frage hier. Guten Tag, ich hab mal wieder ein Problem, folgendes möchte ich erreichen:
Ich habe eine Tabelle mit den Ergebnissen und den Prozentangaben:
local rnd = {
["Kohle"] = 50,
["Eisen"] = 30,
["Redstone"] = 10,
["Gold"] = 5,
["Diamant"] = 5,
}
Nun möchte ich ein zufälliges Ergebnis anhand dieser Prozentzahlen ermitteln, sprich Kohle sollte zu ca. 50% erscheinen. Gesagt getan, habe ich mir ein kleines Script gebastelt:
function stupidRandom()
for i, v in pairs(rnd) do
if math.random(1, v) == 1 then
return i
end
end
return "Kohle"
end
tbl = {}
for i=1, 1000000 do
local s = stupidRandom()
if not tbl[s] then tbl[s] = 0 end
tbl[s] = tbl[s] + 1
end
for i,v in pairs(tbl) do
outputChatBox(i.." = "..v)
end
--[[
Output:
Kohle = 565470
Gold = 135757
Redstone = 94745
Diamant = 171179
Eisen = 32849
]]
Alles anzeigen
Getestet habe ich es mit 1 Millionen Durchläufen. Dies gibt aber relativ willkürliche Werte aus - kein Wunder, da ich das erstbeste Ergebnis returne und einen Fallback-Wert brauche (die "Kohle"), falls mal nichts in der Schleife zurückgegeben wird. Somit kann ich die Prozentangaben sehr einfach manipulieren, indem ich die Anordnung in der Tabelle ändere. Fail also.
Nun aber mein zweiter Versuch, der sehr genaue Ergebnisse liefert:
function randomFromPercent(tblPercents)
local iSum = 0 -- Summe der Prozentangaben
local tblSum = {} --geordnete Tabelle
local i = 0 -- Durchlauf der pairs-Tabelle
for name, perc in pairs(tblPercents) do
i = i + 1
iSum = iSum + perc
tblSum[i] = {iSum = iSum, sName = name}
--outputChatBox(iSum.." = "..name.." "..i)
end
--outputChatBox("---")
if iSum ~= 100 then return false end -- Fehler in der Tabelle werden nicht geduldet!
local iRnd = math.random(1,100)
--outputChatBox("Random = "..iRnd)
local sValue = "" -- Fallback - Wird nie erreicht!
for i,v in ipairs(tblSum) do
local max = 0
if tblSum[i-1] then
max = tblSum[i-1].iSum
--outputChatBox(max)
end
if max <= iRnd and v.iSum >= iRnd then -- Ist der Tabellenwert zwischen dem Random-Wert und dem vorherigen Tabellenwert?
sValue = v.sName
break
end
end
return sValue
end
success = {}
local rnd = {
["Kohle"] = 50,
["Eisen"] = 30,
["Redstone"] = 10,
["Gold"] = 5,
["Diamant"] = 5,
}
for i=1, 1000000 do
local name = randomFromPercent(rnd)
--outputChatBox("-Helau-")
if not success[name] then success[name] = 0 end
success[name] = success[name] + 1
end
local sum = 0
for i,v in pairs(success) do
outputChatBox(i.." = "..v)
sum = sum+v
end
outputChatBox("____________")
outputChatBox("Summe = "..sum)
--[[
Output:
Kohle = 499415
Eisen = 300863
Redstone = 99458
Diamant = 50098
Gold = 50166
____________
Summe = 1000000
]]
Alles anzeigen
Dazu zu sagen ist, dass die erste Schleife vom Prinzip her nicht weggelassen werden kann, wenn man die Tabelle nicht unleserlich schreiben will (Sprich Kohle = 50, Dia = 10, das bedeutet in der Tabelle Kohle = 50, Dia = 60, da ich ja unten die Zahlen der vorherigen mit der jetzigen Tabellenspalte vergleiche). PS: Es hilft auch ungemein die Schleife auf "i=1, 1" zu setzen und alle outputChatBox wieder einzuklammern, um die Funktionsweise zu sehen.
Aber warum erstelle ich dieses Thema, wenn meine Schleife doch funktioniert? Erstens ist der Code relativ lang und unübersichtlich, zweitens brauche ich zwei For-Schleifen, die das ganze auch nicht performanter gestalten. Hat also irgendjemand eine Funktion parat, die eine Tabelle (am besten wie die meine) nimmt und mir dann einen zufälligen Wert gibt?