Zachary Lewis
Level 1
Professional by day, indie by night.


« on: June 18, 2010, 11:42:39 AM » 

I would like to generate weighted random numbers based on a base value, but I'm at a loss as to how to go about doing this.
Example:
In an RPG, whenever I kill a monster, I want to generate a random number of gold pieces for the player to collect between 1 and 1000; however, I want this number to be weighted based on the level of the enemy. If the enemy's level is 1, I want the random number to lean more toward dropping only 1 gold piece; if the enemy's level is 100, I want the random number to lean more toward dropping all 1000 gold pieces.
Any help would be great.



Logged




PGGB


« Reply #1 on: June 18, 2010, 12:15:38 PM » 

I would probably create a probability table that describes how many times out of a hundred the player will get say 110 coins, 1150.. etc. at that level. Then you create a random number between 1 and 100 so you get your range, then you can get another random number that specifies the exact amount.



Logged




Andrew Wolff


« Reply #2 on: June 18, 2010, 12:19:32 PM » 

You could write a function for creating gaussian distributions (bell curve type things) out of your random number generator to get stuff like this this might help a little: http://en.wikipedia.org/wiki/Normal_distributionWith that function you could just plug in a random number and adjust the peak's position depending on the monster's level I'm sure there's a much easier way to do what you want though, but if you're into writing math functions it's fun to mess around with You could also just generate a random number between 1 and 1000 then merge it towards the average number of gold pieces a monster of that level would drop. that would look something like this: //function random(x) returns a number between 0 and x //if your random number generator returns a number between 0 and 1 just multiply it by whatever x would be in the above function
number=random(999)+1; average=max(1,min(1000,monster.level*50)); number=merge_number(number,average,0.5+random(0.5));
function merge_number(x,y,merge) returns x+((yx)*merge) //if you put in 0 it will return x and 1 will return y. anything in between will be proportionally correct
doing that would work and it's pretty flexible but wouldn't necessarily make a very smooth distribution. fiddle around with it and you might get something you like good luck!



Logged




Pishtaco


« Reply #3 on: June 18, 2010, 12:33:38 PM » 

Easy way, although I haven't worked out what distribution it will give you 
Choose a target that you want the number to be weighted towards;
Pick 3 (say) random numbers uniformly from 0 to 1000;
Choose the one that is nearest to your target.



Logged




dcarrigg


« Reply #4 on: June 18, 2010, 02:30:33 PM » 

I got an easy way for you...
Say you have something values with weights like this: 0  5 1  4 2  3 3  2 4  1 5  1
So, 0 gold has highest probability with a weight of 5, 1 gold has a weight of 4, etc.
Roll a random number R between 0 and total weight minus 1 (5+4+3+2+1+1=16 minus 1, 15). Subtract weights from R in order until R is zero.
Ex: R is 4. Start with 0 gold, Rweight is 1 (45=1). Player gets 0 gold.
Ex: R is 10. Start with 0 gold, Rweight is 5. Continue to 1 gold. Rweight is 1 (54=1). Continue to 2 gold. Rweight is 2 (13=2). Player gets 2 gold.
In this example, for each random number, you would get: 0 = 0 Gold 1 = 0 Gold 2 = 0 Gold 3 = 0 Gold 4 = 0 Gold 5 = 1 Gold 6 = 1 Gold 7 = 1 Gold 8 = 1 Gold 9 = 2 Gold 10 = 2 Gold 11 = 2 Gold 12 = 3 Gold 13 = 3 Gold 14 = 4 Gold 15 = 5 Gold
...similar to what you were looking for.
On the two MMORPGs I've worked on, this is how we did our loot drops. We allowed designers to specify loot tables like this with currency as well as items, and assign them to specific types of monsters, treasure chests, etc.
Dave


« Last Edit: June 18, 2010, 02:34:45 PM by dcarrigg »

Logged




sm


« Reply #5 on: June 19, 2010, 05:28:04 AM » 

There are numerous mathematical methods to generate random numbers from (any) probability distributions. One method which comes to my mind is the Inverse transform method ( Wikipedia) which is easy to implement for somewhat "easy" distributions . The previously posted Normal distribution article has also a nice section about generating values from normal distribution. I've also used the Acceptâ€“reject method in my projects to generate random numbers. I didn't find any decent references quickly but you could check this short introduction.



Logged




kiwi


« Reply #6 on: June 19, 2010, 07:32:00 AM » 

I don't think gaussian distribution is suited for this kind of thing, unless you want the monsters with very high levels to give as much gold as the ones with low levels (or use the reverse function to compute the amount of gold based on the level)
Honestly I'd try an approach similar to dcarriggs' because it's easier to adjust the amount of gold if you ever need to balance the game later.



Logged




st33d
Guest


« Reply #7 on: June 19, 2010, 03:38:08 PM » 

If you just want a simple curve, try squaring the random number:
Math.random() * Math.random() * range
You can muck about with this equation to get some other basic curves too.



Logged




Triplefox


« Reply #8 on: June 19, 2010, 09:47:52 PM » 

coinPct = max(monsterLevel/100,1.) coinPct = min(0.,max(1.,coinPct(randomPct/2)+random()*randomPct)) coins = coinPct*1000
This pseudocode gives you a random distribution based on a percentage of the number of coins available. I cap monsterLevel at 100 first, which means that some variation below 1000 coins will always occur no matter how high the monster level goes; if you want it to hardcap at 1000 if monster level is really high, remove that first max(). Then I center the random distribution around the expected percentage given from the level. Finally, I generate a number of coins based on the randomized percentage. If you want the randomness to have a less noisy distribution, many methods are available such as the Gaussian ones mentioned earlier in this thread, and I would recommend looking at the wiki entry on normal distributions for more details. An advantage of the percentage method is that you can apply a curve at the percentage step without tangling it inside the coinrandomness step  so if, for example, you want the number of coins to increase with the square of monster level rather than linearly, you can simply add coinPct = coinPct*coinPct after the first step.



Logged




muku


« Reply #9 on: June 21, 2010, 03:25:05 AM » 

coinPct = max(monsterLevel/100,1.) coinPct = min(0.,max(1.,coinPct(randomPct/2)+random()*randomPct)) coins = coinPct*1000
I think your mins and maxes got mixed up? Far as I can tell, every max should be a min and vice versa. My first idea was a normal (Gaussian) distribution, it seems like the obvious choice. I really like Pishtaco's idea now though. You can play with the number of candidates to get a tighter distribution; 3 seems awfully low, would be pretty common to have a lowlevel monster drop a huge pile of loot (unless that's what you want of course).



Logged




bateleur


« Reply #10 on: June 21, 2010, 03:33:49 AM » 

Easy way, although I haven't worked out what distribution it will give you 
Choose a target that you want the number to be weighted towards;
Pick 3 (say) random numbers uniformly from 0 to 1000;
Choose the one that is nearest to your target.
This method is superbly elegant  way better than what I was about to suggest! Also, I love the way you can control the deviation by adjusting the size of the pool of numbers you choose the closest from.



Logged




dukope


« Reply #11 on: June 21, 2010, 05:51:34 AM » 

I suck at pure math, so I usually solve this the (manly) programmer way with probability tables. Those only work for discrete values, but you could use PGGB's method to fake continuity. Easy way, although I haven't worked out what distribution it will give you  Choose a target that you want the number to be weighted towards; Pick 3 (say) random numbers uniformly from 0 to 1000; Choose the one that is nearest to your target.
Awesome. I'd really like to see the distribution on that. So simple.



Logged




muku


« Reply #12 on: June 21, 2010, 06:14:04 AM » 

Easy way, although I haven't worked out what distribution it will give you  Choose a target that you want the number to be weighted towards; Pick 3 (say) random numbers uniformly from 0 to 1000; Choose the one that is nearest to your target.
Awesome. I'd really like to see the distribution on that. So simple. Yeah, me too, and I'm procrastinating at work again... with 3 candidates: with 10 candidates: I thought about it a bit and it shouldn't be too hard to derive the distribution function. Basically I think you get another power of your original cumulative density function per candidate, so for 2 it's squared.



Logged





Craig Stern


« Reply #14 on: August 13, 2010, 05:40:48 AM » 

My first thought was a probability table. That's what I use to select enemies for the randomly generated battles in Telepath RPG: Servants of God. It's a pretty easy way to affect how common or rare certain enemy spawns areI can't think of any reason that wouldn't work for amounts of gold dropped. This way is really clever though: Easy way, although I haven't worked out what distribution it will give you 
Choose a target that you want the number to be weighted towards;
Pick 3 (say) random numbers uniformly from 0 to 1000;
Choose the one that is nearest to your target.



Logged




Nugsy


« Reply #15 on: August 13, 2010, 06:44:25 AM » 

(MobLevel*Random(75 to 125))/100
75 to 125 gives you 25% gold below the mobs level, and 25% above. As it stands, this gives rather narrow values, usually 1 or +1 gold. But it can be changed pretty easily to give a wider range of values.
Edit: Forgot to mention that the number will need to be rounded up/down.


« Last Edit: August 13, 2010, 06:52:10 AM by Nugsy »

Logged




Epitaph64


« Reply #16 on: August 15, 2010, 12:10:46 PM » 

Maybe I'm missing something, but why not just generate a random float value between 1 and 10, and then multiply it by the monster's level? Unless you want, for instance, a level 1 monster to have a small chance to drop the maximum of 1000, but for most RPGs this wouldn't really make sense, but of course that is up to you. You may have to do a hack like generate a 100 times larger integer and then divide it by 100 into a float/double. Then you would just do:
gold_dropped = Math.floor(randomFloat * 10);


« Last Edit: August 15, 2010, 12:15:18 PM by Epitaph64 »

Logged




st33d
Guest


« Reply #17 on: August 17, 2010, 12:49:42 AM » 

But that's not a weighted random number I don't think.
The point of the effort is to skew the difficulty so that beginners can learn the mechanics before tackling the big monsters.



Logged




