Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411430 Posts in 69363 Topics- by 58416 Members - Latest Member: JamesAGreen

April 19, 2024, 10:29:41 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)How do I generate weighted random numbers?
Pages: [1]
Print
Author Topic: How do I generate weighted random numbers?  (Read 17898 times)
Zachary Lewis
Level 1
*


Professional by day, indie by night.


View Profile WWW
« 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
Level 8
***



View Profile
« 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 1-10 coins, 11-50.. 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
andy wolff
Level 10
*****


-------


View Profile
« 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_distribution
With 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:
Code:
//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+((y-x)*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
Level 10
*****


View Profile WWW
« 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
Level 0
***

Software Neurosurgeon


View Profile WWW
« 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, R-weight is -1 (4-5=-1). Player gets 0 gold.

Ex: R is 10. Start with 0 gold, R-weight is 5. Continue to 1 gold. R-weight is 1 (5-4=1). Continue to 2 gold. R-weight is -2 (1-3=-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

Check it out! www.retroaffect.com
sm
Level 0
*



View Profile WWW
« 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 Smiley. 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
Level 0
***


View Profile WWW
« 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
Level 9
****



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

Code:
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 hard-cap 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 coin-randomness 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
Level 10
*****


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

Code:
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 low-level monster drop a huge pile of loot (unless that's what you want of course).
Logged
bateleur
Level 10
*****



View Profile
« 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! SmileyHand Thumbs Up Right

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
Level 3
***


View Profile WWW
« 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
Level 10
*****


View Profile
« 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
dougfinn
TIGBaby
*


View Profile
« Reply #13 on: August 04, 2010, 08:09:40 PM »

You might want to take a look at these pages:

http://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/

http://www.petrileskinen.fi/random/randomDistribution.html

Cheers!
Logged
Craig Stern
Level 10
*****


I'm not actually all that stern.


View Profile WWW
« 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 are--I 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
Level 10
*****



View Profile
« 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
Level 1
*



View Profile WWW
« 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
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic