SonicSonedit Posted January 22, 2014 Share Posted January 22, 2014 (edited) This feedback article/open letter will cover why RNG is flawed and how to fix RNG itself (without tokens or anything). TL; DR: Current RNG gives flawed resulsts (like 40% to get Bronco Prime Barrel from T3 cap and reduced chance for other items) and here is a solution (working program code included) how to fix it and make RNG nearly perfectly fair. TheoryIn Warframe, when we say RNG we don't actually mean random seed feed/scheldue/generating algorithm itself, but the system which determines what rewards we will obtain in general. In other words, the RNG itself is not what we need to fix, but how we use numbers which it provides: RNG is just RNG, it does what it does - spits out numbers randomly. But how we use them is a different story.Lets assume we have a drop table(this drop table is only for testing purposes and does not relate to actual reward table)The RNG provided us with number 10. What does it mean? What do we apply it for? There are 2 most common RNG algorithms, and I will review both of them.Simple RNGThis algorithm rolls a dice for every item in list and checks if item passed. If not, it rolls for next item and keeps on until we get a reward. If the end of the list is reached, it starts over.Logic:1) Roll a dice from 0 to 99.2) Check if item chance is lower then rolled dice3) If it is lower - select this item as a reward and exit!4) If not, roll for next item in list.5) If end of list is reached, start from first item in list.FAQ: ("0..99? but 99 is not 100%! Why not 0..100??" You may ask. Well, 0..99 is actually 100 numbers (0 included). And also we compare if dice is LOWER (not lower or equal) than item chance. Therefore item with 1% will only pass for the dice value of 0, which has 1% when rolling 0..99) Code: code tag is going crazy. If anyone knows how can I make code readable - much appreciated.procedure TSimpleRNG.Execute;vari: Integer;RNGing: Boolean;tempchance, tempresult: integer;templabel:TLabel;beginTestsCount:=0;for i:= 0 to 6 do // reseting test valuesItemResult:=0;while not(Terminated) and not(Application.Terminated) do beginInc(TestsCount); // Tests Count +1if not(DontUpdateGUI) then form1.MemoLog.Lines.Add('T3 Capture run #'+IntToStr(TestsCount)+':'); // debug infoRNGing:=True; // getting random reward is in progresswhile (RNGing) and not(Terminated) and not(Application.Terminated) do beginfor i:= 0 to 6 do begin // going through rewards listRandomize; // reset random seedRNGResult:=Random(100); // get random value from 0 to 99 with new seedif not(DontUpdateGUI) then form1.MemoLog.Lines.Add('Rolling Dice for item '+IntToStr(i)+': Item chance = '+IntToStr(ItemChance)+', rolled '+IntToStr(RNGResult)); // debug infoif RNGResult<ItemChance then begin // if item passedif not(DontUpdateGUI) then form1.MemoLog.Lines.Add('Item '+IntToStr(i)+' was obtained from T3 capture run #'+IntToStr(TestsCount)+':'); // debug infoInc(ItemResult); // amount of passed item obtained from void runs +1RNGing:=False; // we got our random reward and can exit endless cycle nowBreak; // exiting i loopend;Sleep(1); // 1msec delay to make sure next random seed IS randomend;Synchronize(UpdateGUI); // updating GUI if neededend;end;end; Result:Holly Dolly! Isn't this exactly what we see in-game? Do you know why you can build a palisade from Orthos Prime Handles? Because hello 40% of getting Orthos Prime Handle from T2 cap!Theory:Why this result is SO flawed?Well, the reason is pretty obvious if you are familiar with probability theory. For people who a familiar: , so yeah, this pretty much explains it.For people who are not familiar with it, I will try to explain it as accessibly as I can.Lets assume we flip a coin. If we get heads, we take a reward and go away, if we get tails, we flip coin for the next reward. What is the chance of getting first reward? Obviously 50%. But what is the chance of getting the second reward? It's actually 25%. Why? Because there is 50% that we get head and take first reward and go away. And only if we do not take first reward, we have a chance to get second, by flipping a coin, hence reducing the chance of acquiring 2nd reward by half (Because we start from 1st reward every time). For 3rd reward the chance will be 12.5%, for 4th 6.25% and so on.Summing things up: If we use simple RNG algorithm, RNG will favor items that come first in list much much more then items in the end of list. Thats why the chance of getting newly added items (which are added in the end of reward list) is super low. Yes, I'm talking about Ember Prime parts here.So, moving on.There is another commonly used RNG algorithm, which I will call "Advanced RNG".Advanced RNGThis algorithm first selects a dice size depending on highest item chance and then rolls a dice, checking which items have passed. Then it randomly selects an item from the passed items pool.Logic:1) Select dice size (for our drop table that will be 25).2) Roll a dice from 0 to 24.3) Check which items passed and add them to the "passed items" pool.4) Pull random item for passed items pool.Code: procedure TAdvancedRNG.Execute;vari: Integer;DiceSize: Integer;PassedRewards: array [0..6] of integer;PassedRewardsCount: Integer;RewardWeight: array [0..6] of integer;MinimalWeight: integer;beginTestsCount:=0;for i:= 0 to 6 do // reseting test valuesItemResult:=0;DiceSize:=0;for i:= 0 to 6 do // determinating dice size to optimize algorithmif ItemChance>DiceSize thenDiceSize:=ItemChance;while not(Terminated) and not(Application.Terminated) do beginInc(TestsCount); // Tests Count +1if not(DontUpdateGUI) then form1.MemoLog.Lines.Add('T3 Capture run #'+IntToStr(TestsCount)+':'); // debug infoPassedRewardsCount:=0; // passed rewards list is emptyRandomize; // reset random seedRNGResult:=Random(DiceSize); // get random value from 0 to DiceSize. DiceSize is item rewards highest chance (25 probably).if not(DontUpdateGUI) then form1.MemoLog.Lines.Add('Rolled: '+IntToStr(RNGResult)); // debug infofor i:= 0 to 6 do // going through rewards listif RNGResult<ItemChance then begin // if item passedif not(DontUpdateGUI) then form1.MemoLog.Lines.Add('Item '+IntToStr(i)+' passed!'); // debug infoPassedRewards[PassedRewardsCount]:=i; // adding item to passed rewards listInc(PassedRewardsCount); // passed rewards count +1end;Sleep(1); // 1msec delay to make sure next random seed IS randomRandomize; // reset random seedRNGResult:=Random(PassedRewardsCount); // get random value from 0 to (passed rewards list size -1)if not(DontUpdateGUI) then form1.MemoLog.Lines.Add('Item #'+IntToStr(PassedRewards[RNGResult])+' was selected!'); // debug infoInc(ItemResult[PassedRewards[RNGResult]]); // amount of item (randomly selected from passed rewards list) obtained from void runs +1Synchronize(UpdateGUI); // update GUI if neededend;end; Result:Well, this does look better. At least we can have a ton of forma now. But still, results are flawed. Why is that?This is because all items have same chance of being pulled from passed rewards pool while some item have a much lower chance to be in passed items pool then others.Lets say we rolled 20. Forma and Bronco Barrel have passed and then Bronco is pulled from passed items pool. Next time we rolled 7. Forma, Bronco Barrel, Bronco Receiver and Orthos Blade have passed. But guess what? We pulled Bronco Barrel from passed rewards pool!Summing things up: this algorithm favors large numbers.But isn't there anything that can be done!? Maybe sacrafices of virgin Novas will appease RNG gods? Not really, but we can try and fix the algorithm itself.So, the problem is: items which have a lower chance of being in passed items pool have a same chance to be pulled from this pool as items which pass almost every time. How can we fix it? We can try to pull items with lowest pass chance from passed items chance, but this is a bad idea. Lets assume we have item with 10% to pass and 9%. The will almost always pass together due to small selection space beetween 9% and 10% and we will always pull item with 9%, which will make item with 10% nearly extinct, it will actually have less then 1% of being rolled. So what else can we do?We can introduce weights!What weights? Item weights. Each item will have "weight" - the more item was pulled from passed item pool the "heavier" it will be. And every time we get an passed items pool, we filter it from the most heavy items.Logic:1) Select dice size (for our drop table that will be 25).2) Roll a dice from 0 to 24.3) Check which items passed and add them to the "passed items" pool.4) Search for lowest weight of items within passed items pool and select this weight as minimal.5) Remove all items which are above minimal weight from passed items pool.6) Pull random item from filtered passed items pool.7) Increase weight of pulled item.Code: procedure TAdvancedRNG.Execute;vari: Integer;DiceSize: Integer;PassedRewards: array [0..6] of integer;PassedRewardsCount: Integer;RewardWeight: array [0..6] of integer;MinimalWeight: integer;beginTestsCount:=0;for i:= 0 to 6 do // reseting test valuesItemResult:=0;DiceSize:=0;for i:= 0 to 6 do // determinating dice size to optimize algorithmif ItemChance>DiceSize thenDiceSize:=ItemChance;if WeightRewards thenfor i:= 0 to 6 do // reset weightsRewardWeight:=0;while not(Terminated) and not(Application.Terminated) do beginInc(TestsCount); // Tests Count +1if not(DontUpdateGUI) then form1.MemoLog.Lines.Add('T3 Capture run #'+IntToStr(TestsCount)+':'); // debug infoPassedRewardsCount:=0; // passed rewards list is emptyRandomize; // reset random seedRNGResult:=Random(DiceSize); // get random value from 0 to DiceSize. DiceSize is item rewards highest chance (25 probably).if not(DontUpdateGUI) then form1.MemoLog.Lines.Add('Rolled: '+IntToStr(RNGResult)); // debug infofor i:= 0 to 6 do // going through rewards listif RNGResult<ItemChance then begin // if item passedif not(DontUpdateGUI) then form1.MemoLog.Lines.Add('Item '+IntToStr(i)+' passed!'); // debug infoPassedRewards[PassedRewardsCount]:=i; // adding item to passed rewards listInc(PassedRewardsCount); // passed rewards count +1end;if WeightRewards then begin // here come the weights!MinimalWeight:=0; // reset minimal weightfor i:= 0 to PassedRewardsCount-1 do // determinating minimal weightif (RewardWeight[PassedRewards]<MinimalWeight) or (MinimalWeight=0) then // if minimal weight is 0 (reseted) or above item weight, set it to item weightMinimalWeight:=RewardWeight[PassedRewards];i:=0;if not(DontUpdateGUI) then form1.MemoLog.Lines.Add('Minimal weight: '+IntToStr(MinimalWeight)); // debug info thenwhile i<PassedRewardsCount do begin // didnt use for here because working with cycle control varsif not(DontUpdateGUI) then form1.MemoLog.Lines.Add('Item '+IntToStr(PassedRewards)+' weight: '+IntToStr(RewardWeight[PassedRewards])); // debug info thenif RewardWeight[PassedRewards]>MinimalWeight then begin // remove everything which above minimal weightif not(DontUpdateGUI) then form1.MemoLog.Lines.Add('Item '+IntToStr(PassedRewards)+' was removed due to overweight.'); // debug info thenmove(PassedRewards[i+1], PassedRewards, (PassedRewardsCount-i-1)*SizeOf(PassedRewards[0])); // remove overweighted reward from passed rewards listDec(PassedRewardsCount); // decrease passed rewards counterDec(i);end;Inc(i);end;end;Sleep(1); // 1msec delay to make sure next random seed IS randomRandomize; // reset random seedRNGResult:=Random(PassedRewardsCount); // get random value from 0 to (passed rewards list size -1)if not(DontUpdateGUI) then form1.MemoLog.Lines.Add('Item #'+IntToStr(PassedRewards[RNGResult])+' was selected!'); // debug infoInc(ItemResult[PassedRewards[RNGResult]]); // amount of item (randomly selected from passed rewards list) obtained from void runs +1if WeightRewards thenInc(RewardWeight[PassedRewards[RNGResult]]); // increase weight of the rewards if weight are enabledSynchronize(UpdateGUI); // update GUI if neededend;end; Result:Well this does look better. But still, RNG does favor large numbers a lot if we use Advanced RNG, even if we add weights.But wait...maybe we can also add some sort of weights or something for Simple RNG? Lets see!Back to Simple RNGSo what was our problem with Simple RNG? Oh yeah it favored items which were first in list and hated items in the end of list. How can we fix it. Actually, quite simple: move item we just got to the end of the list! Lets try and see what happens.Logic:1) Roll a dice from 0 to 99.2) Check if item chance is lower then rolled dice3) If it is lower - select this item as a reward and exit!4) If not, roll for next item in list.5) If end of list is reached, start from first item in list.6) move the reward we got to the very end of the list, without shifting elements which go before it.For the last action (#6) I decided to draw a picture:Code: procedure TSimpleRNG.Execute;vari: Integer;RNGing: Boolean;tempchance, tempresult: integer;templabel:TLabel;beginTestsCount:=0;for i:= 0 to 6 do // reseting test valuesItemResult:=0;while not(Terminated) and not(Application.Terminated) do beginInc(TestsCount); // Tests Count +1if not(DontUpdateGUI) then form1.MemoLog.Lines.Add('T3 Capture run #'+IntToStr(TestsCount)+':'); // debug infoRNGing:=True; // getting random reward is in progresswhile (RNGing) and not(Terminated) and not(Application.Terminated) do beginfor i:= 0 to 6 do begin // going through rewards listRandomize; // reset random seedRNGResult:=Random(100); // get random value from 0 to 99 with new seedif not(DontUpdateGUI) then form1.MemoLog.Lines.Add('Rolling Dice for item '+IntToStr(i)+': Item chance = '+IntToStr(ItemChance)+', rolled '+IntToStr(RNGResult)); // debug infoif RNGResult<ItemChance then begin // if item passedif not(DontUpdateGUI) then form1.MemoLog.Lines.Add('Item '+IntToStr(i)+' was obtained from T3 capture run #'+IntToStr(TestsCount)+':'); // debug infoInc(ItemResult); // amount of passed item obtained from void runs +1RNGing:=False; // we got our random reward and can exit endless cycle nowif ShiftRewards then begin // here goes shifting!if i<Length(ItemChance)-1 then begin // if item is NOT last in listtempchance:=ItemChance;tempresult:=ItemResult; // store item information in temp variablestemplabel:=LabelItemResult;move(ItemChance[i+1], ItemChance, (Length(ItemChance)-i-1)*SizeOf(ItemChance[0])); // shift chance arrayItemChance[Length(ItemChance)-1]:=tempchance; // restore last index (restore moved item chance)move(ItemResult[i+1], ItemResult, (Length(ItemResult)-i-1)*SizeOf(ItemResult[0])); // shift result (obtained count) arrayItemResult[Length(ItemResult)-1]:=tempresult; // restore last indexmove(LabelItemResult[i+1], LabelItemResult, (Length(LabelItemResult)-i-1)*SizeOf(LabelItemResult[0])); // shift GUI arrayLabelItemResult[Length(ItemResult)-1]:=templabel; // restore last index// it would be much better to simply create a class for item and move the class within array instead of each element individually, but im too lazy. maybe later.end;end;Break; // exiting i loopend;Sleep(1); // 1msec delay to make sure next random seed IS randomend;Synchronize(UpdateGUI); // updating GUI if neededend;end;end; Result:Woah! This is nearly perfect result!For reference, here are nominal values:Bronco Prime Barrel: 30,875%Bronco Prime Receiver: 12,35%Forma: 30,875%Forma: 6,175%Orthos Prime Blade:12,35%Emper Prime Chassis: 1,235%Ember Prime Systems: 6,175%FAQ: Summ of all item chances: 81; 100/81=1,235 therefore all rewards amount should be 23,5% bigger than it's chance Yeah, the numbers deviant a little, but they are very very close to perfect values.Summing Everything UpCan DE fix the RNG?Yes, they surely can. They have everything they need now - even the source code for RNG algorithm.What will it take?They will have to store shifted rewards arrays on either client of server side. Preferably server.How much of bytes is this?This depends on how many rewards in reward list. For Void its about 15 items. Int32 has a size of 4 bytes. Therefore it will be 4*15*5=300 bytes for void drop tables.Lorane_Airwing was kind enough to calculate that it will take 4,5gb to store all reward tables on server for 3m players (1722 bytes per player), check out his post: https://forums.warframe.com/index.php?/topic/166725-rng-explanation-theory-algorithms-practice/?p=1955576RNG Test tool - both source code & exe: downloadP.S.Please let me know if you see any logic flaws, typos, etc! Edited January 23, 2014 by SonicSonedit Link to comment Share on other sites More sharing options...
SpilockT_T Posted January 22, 2014 Share Posted January 22, 2014 DE, you need to learn from OP. Link to comment Share on other sites More sharing options...
Bazools Posted January 22, 2014 Share Posted January 22, 2014 And thats how it's done! DE time to make changes don't u think? Dude u deserve a hug. Awesome post! Link to comment Share on other sites More sharing options...
Namacyst Posted January 22, 2014 Share Posted January 22, 2014 (edited) -snip- Back to Simple RNGSo what was our problem with Simple RNG? Oh yeah it favored items which were first in list and hated items in the end of list. How can we fix it. Actually, quite simple: move item we just got to the end of the list! Lets try and see what happens.Logic:1) Roll a dice from 0 to 99.2) Check if item chance is lower then rolled dice3) If it is lower - select this item as a reward and exit!4) If not, roll for next item in list.5) If end of list is reached, start from first item in list.6) move the reward we got to the very end of the list, without shifting elements which go before it. -snip- DE! Edited January 22, 2014 by Namacyst Link to comment Share on other sites More sharing options...
xWindScar Posted January 22, 2014 Share Posted January 22, 2014 For anybody who doesn't understand the code or just wants a suuuuper simplified explanation for his RNG fix idea: When you get a reward, that reward becomes less likely for you to get again until other rewards have been received. Super kudos to you, sir. This is the most thorough user idea I have ever seen submitted about anything ever. Link to comment Share on other sites More sharing options...
Dequire Posted January 22, 2014 Share Posted January 22, 2014 ...Dude. Go sign up with DE and slap them. Please. PLEASE slap them with this code. Link to comment Share on other sites More sharing options...
Lorane_Airwing Posted January 22, 2014 Share Posted January 22, 2014 (edited) From what i understand each mission simply uses a table shared between all missions of the same type, some even lack end mission reward tables! meaning we can get the estimated storage MUCH smaller :DUsing your estimate formula of 4*reward# = byte count I have calculated all the tables I'm aware of.( wiki helped a ton )<void defense, NOTE apparently these are changing to endless in U12? >void defense - tier 1 - 7 rewards - 28 bytesvoid defense - tier 2 - 7 rewards - 28 bytesvoid defense - tier 3 - 7 rewards - 28 bytesvoid survival - tier 1 - 10 rewards - 40 bytesvoid survival - tier 2 - 11 rewards - 44 bytesvoid survival - tier 3 - 8 rewards - 32 bytesvoid capture - tier 1 - 8 rewards - 32 bytesvoid capture - tier 2 - 9 rewards - 36 bytesvoid capture - tier 3 - 8 rewards - 32 bytesvoid exterminate - tier 1 - 7 rewards - 28 bytesvoid exterminate - tier 2 - 7 rewards - 28 bytesvoid exterminate - tier 3 - 6 rewards - 24 bytesvoid mobile defense - tier 1 - 7 rewards - 28 bytesvoid mobile defense - tier 2 - 6 rewards - 24 bytesvoid mobile defense - tier 3 - 7 rewards - 28 bytesOD defense - no tier - 7 rewards - 28 bytesOD survival - no tier - 8 rewards - 32 bytesOD capture - no tier - 25 rewards?< uses normal capture table? > - 100 bytes?OD exterminate - no tier - no rewards?< uses normal exterminate table? > - 0 bytes?< defense tiers appear to be seperated by faction, i assume here that they each have faction specific tables per tier >endless defense - tier 1 grineer - 15 rewards - 60 bytesendless defense - tier 2 grineer - 23 rewards - 92 bytesendless defense - tier 3 grineer - 17 rewards - 68 bytesendless defense - tier 1 corpus - 15 rewards - 60 bytesendless defense - tier 2 corpus - 23 rewards - 23 bytesendless defense - tier 3 corpus - 17 rewards - 68 bytesendless defense - tier 1 infested - 15 rewards - 60 bytesendless defense - tier 2 infested - 23 rewards - 23 bytesendless defense - tier 3 infested - 17 rewards - 68 bytes< possibly simplified, they may be seperated into 5 minute table intervals >survivial - tier 1 - 29 rewards - 116 bytessurvivial - tier 2 - 33 rewards - 132 bytessurvivial - tier 3 - 34 rewards - 136 bytescapture - no tiers - 25 rewards - 100 bytesspy - no tiers - 24 rewards - 96 bytes< some missions do not appear to have clear reward tables >exterminate - no tiers - no rewards....?rescue - no tiers - no rewards....?deception - no tiers - no rewards....?mobile defense - no tiers - no rewards....?sabotage - no tiers - no rewards....?1722 bytes total for all unique tables1.68 kilobytes of data per player; so... with 3 million estimated players.... 4.80 gigabytes, MUCH smaller than my original calculations ( with the improper math ) Edited January 22, 2014 by Lorane_Airwing Link to comment Share on other sites More sharing options...
SonicSonedit Posted January 22, 2014 Author Share Posted January 22, 2014 (edited) Lorane_Airwing Yes, some tables are indeed shared. ODD used Xini reward table for a very long time. A lot of missions still use some shared tables (But all derelict mission have unique tables by now). And yes. some missions dont have reward tables. Using your estimate formula of 4*reward#*5 = byte count I have calculated all the tables I'm aware of.( wiki helped a ton )You misunderstood a little bit here. It wa 4*reward#*5 because there are 5 void mission types. So actually it's 4*rewardcount*missoncount. Edited January 22, 2014 by SonicSonedit Link to comment Share on other sites More sharing options...
Lorane_Airwing Posted January 22, 2014 Share Posted January 22, 2014 (edited) You misunderstood a little bit here. It wa 4*reward#*5 because there are 5 void mission types. So actually it's 4*rewardcount*missoncount. I'll go back and change the data than. I was a bit unsure what the 5 was for but decided to include it. EDIT: math has been updated and gives us a MUCH smaller number. 1.68 kilobytes per player, and around 5 gigs for all of them together. heck, if we wanted to hit my old calculation of 26 gigabytes warframe would need 16227962 players/accounts! Edited January 22, 2014 by Lorane_Airwing Link to comment Share on other sites More sharing options...
Annie-Mae Posted January 24, 2014 Share Posted January 24, 2014 Wow this deserves some attention! Link to comment Share on other sites More sharing options...
Phatose Posted January 24, 2014 Share Posted January 24, 2014 (edited) All these proposed methods are completely insane. Consider, if you have 4 items, one is 50% to drop, and the others are 25% to drop, are you going to make 5+ rolls to decide what you get? Or are you going to say "Roll a 4 sided die. 1 or 2 get item A, 3 is B, and 4 is C?" There's a much, much simpler way to get a purely linear and predictable drop, with precisely one roll. And given the way defense rewards are awarded - with a linear table, and a random stepping number, it's almost certainly what's already in use. The method is this: Have a rewards table. Every item in the rewards table has a probability value. This value is a simple integer - no percentages, no nothing. When you make a roll, first you sum up all the values in the table. Then you roll a number between 0 and that sum, and assign it to a variable. Start at the top of the list. Subtract that item's probability from your variable. If your variable is now negative, that item is your reward. If not, move on to the next item and repeat. Unbelievably easy to implement, and behaves exactly as you'd expect. To get the actual percentage of any particular drop in the table, just add up all probabilities, and divide the item's probability value by that. No rolling for rolls, no meta-probability games. Just a basic linear distribution innately equal to your listed values. Edited January 24, 2014 by Phatose Link to comment Share on other sites More sharing options...
OmgLasersPewPew Posted January 24, 2014 Share Posted January 24, 2014 Can't upvote you enough OP, this is amazing! DE please make this happen! Link to comment Share on other sites More sharing options...
notionphil Posted January 24, 2014 Share Posted January 24, 2014 skimmed bc @ work but.... What about the other basic RNG algo that only has a single dice roll. It doesn't use a 'pass check' to see if the dice is under the 'rarity value' of each item...and instead each item has a set range. if the dice value is within that range, that is always the reward. EX: 0-2 = orthos prime blade 3-40 = forma BP 41-55 = ember p systems 56-98 = ember p helm 99 = forma so, some single roll examples: 1 = orthos prime blade 5 = forma BP 99 = forma etc... Link to comment Share on other sites More sharing options...
(PSN)feel-T_ornado Posted March 15, 2014 Share Posted March 15, 2014 Actually, RNG is horrendous... nuff said. Oh wait, that wasn't in discussion, silly me. lol Link to comment Share on other sites More sharing options...
Zerrien Posted March 15, 2014 Share Posted March 15, 2014 (edited) What about the other basic RNG algo that only has a single dice roll. Honestly, I appreciate OP's work, but, uh, this is how you do it. His RNG is... uh, ... awful. I'm sorry OP, but that's not how you do it. $itemArray = Array(0, 0, 0, 0, 0);for($i = 0; $i < 10000; $i++) { $rand = rand(0, 99); //Generates a value from 0 to 99. 100 different values. if($rand < 1) { //If it is 0, (1% of the time) $itemArray[0] += 1; } else if ($rand < 6) { //If it's less than 6, and not 0 (5% of the time, since 0 is already used.) $itemArray[1] += 1; } else if ($rand < 31) { //If it's less than 31, and not 0-6 (25% of the time, since 0-6 is already used.) $itemArray[2] += 1; } else if ($rand < 61) { //If it's less than 61, etc $itemArray[3] += 1; } else { //Else, 61-99 = 39 $itemArray[4] += 1; }} Finally: here is a trial of the above RNG after 10,000,000 cases. And, for a working example of the exact above code (which is written in PHP): http://goaggro.com/warframeGenome/rngTest.php Edited March 15, 2014 by Zerrien Link to comment Share on other sites More sharing options...
(PSN)vivan000 Posted March 15, 2014 Share Posted March 15, 2014 (edited) Yeah, the topic is hillarious. I mean, "how to make broken RNG" is valid part, however "how to fix it"... Anyways, devs said that problem is not how you select reward, problem is how you generate random number. I mean that "Random(100)" in OP post or "rand(0, 99)" in post above is just too slow. https://forums.warframe.com/index.php?/topic/128402-rng-algorithm-bugschanges/ It's highly arguable (for drops they can use such slow algorithm), but they closed that topic. Edited March 15, 2014 by (PS4)vivan000 Link to comment Share on other sites More sharing options...
WhisperByte Posted March 15, 2014 Share Posted March 15, 2014 Yeah, the topic is hillarious. I mean, "how to make broken RNG" is valid part, however "how to fix it"... Anyways, devs said that problem is not how you select reward, problem is how you generate random number. I mean that "Random(100)" in OP post or "rand(0, 99)" in post above is just too slow. https://forums.warframe.com/index.php?/topic/128402-rng-algorithm-bugschanges/ It's highly arguable (for drops they can use such slow algorithm), but they closed that topic. Thanks. I've been looking for that thread. Why is it not in Developer Workshop is beyond me... Anyway. Around the release of Ember Prime their algorithms got reverted to the "bugged" state where you get the same PP String over and over and over again while running T2 caps. Time to hit support Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now