• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[Trigger] (maths) higher/lower random outcome based on an int

Status
Not open for further replies.
Level 6
Joined
Jan 8, 2009
Messages
140
I want to have an item array with maybe 20 or so items in it. there will also be an integer that will range from 1-100. if the int is 10 for example there should be a higher chance of getting a lower item out of the array, vice versa if it was 90.

short of having a whole range of if/then/elses is there a better way to do this? some sort of formula I could use to generate a number between 1 and 20 based on how high a particular int variable is?
 
Level 21
Joined
Mar 27, 2012
Messages
3,232
JASS:
function Stuff takes integer j returns integer
    integer i = 100
    loop
        exitwhen j < 1
        set i = GetRandomInt(1,i)
        set j = j - 1
    endloop
    return i
endfunction

Basically if you input 1, then each number has an equal chance to come(1-100)
If you input 2, then 1 is twice as likely to come as 100.
If you input 3, then 1 is 4 times as likely as 100.
If you input 4, then 1 is 8 times as likely as 100.
 
Level 6
Joined
Jan 8, 2009
Messages
140
JASS:
function Stuff takes integer j returns integer
    integer i = 100
    loop
        exitwhen j < 1
        set i = GetRandomInt(1,i)
        set j = j - 1
    endloop
    return i
endfunction

Basically if you input 1, then each number has an equal chance to come(1-100)
If you input 2, then 1 is twice as likely to come as 100.
If you input 3, then 1 is 4 times as likely as 100.
If you input 4, then 1 is 8 times as likely as 100.

hmm, sort of what i'm after if I reversed the numbers round. however i'm looking for something that would do say...

input 1, then 1 is more likely than 2 which is more likely than 3...
input 20 then 5 is more likely than 4 which is more likely than 3... & 5 is more likely than 6 which is more likely than 7...
input 50 then 10 is more likely than numbers above and below it, with chances for the further numbers becoming less and less likely
 
Level 21
Joined
Mar 27, 2012
Messages
3,232
hmm, sort of what i'm after if I reversed the numbers round. however i'm looking for something that would do say...

input 1, then 1 is more likely than 2 which is more likely than 3...
input 20 then 5 is more likely than 4 which is more likely than 3... & 5 is more likely than 6 which is more likely than 7...
input 50 then 10 is more likely than numbers above and below it, with chances for the further numbers becoming less and less likely

Hmm. There might be a way to do it with my method, but I'm not sure.
You could try using my method and a reversed version of it, then taking the average result.
 
Level 25
Joined
Jul 10, 2006
Messages
3,315
It sounds like you want 100 distinct drop cases.

Here's another way to do it:

Make an integer array to record drop priority for each item.
You add all of these integers together to get your total, and this will be the max for the range of your random number.
When you get a random integer, you use a for loop to see in which set the integer belongs.

For instance, we have
Item[1] = claws
Priority[1] = 5
Item[2] = ring
Priority[2] = 20
Item[3] = potion
Priority[3] = 25

This will mean that ring is 4 times as likely as claw to drop, and potion 5 times as likely as claw.
Adding them all together, you get 50.
So when you roll a random number for the drop, you roll from 1 to 50.
Now, loop through each item and is to which the number belongs.
Say we rolled a the number 19.
Code:
Set Position = 1
Loop A from 1 to 3 (we have 3 item types)
 If ((RandomResult Greater than or equal to Position) and (RandomResult Less than (Position + Priority[A]))) 
 Then //this is your item
 Else //continue
 Set Position = Position + Priority[A]
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
If I'm not mistaken, you're looking for a normal distribution?
http://en.wikipedia.org/wiki/Normal_distribution

You can get a normal distribution simply by rolling multiple dice. For example, if you roll 2 dice (6-sided), you're more likely to roll a 7 than anything else. You're least likely to roll a 2 or 12.

JASS:
function GetNormalRandomInt takes integer lower, integer higher returns integer
    local real deltaHalf = (higher - lower) / 2
    return lower + GetRandomInt(0, deltaHalf) + GetRandomInt(0, deltaHalf)
endfunction

GetNormalRandomInt(0, 100) would be most likely to return 50, with 49 and 51 being less likely, and 0 and 100 being least likely. It should be relatively straight forward to adapt this function so it is centered around a different number.
 
Level 6
Joined
Jan 8, 2009
Messages
140
If I'm not mistaken, you're looking for a normal distribution?
http://en.wikipedia.org/wiki/Normal_distribution

You can get a normal distribution simply by rolling multiple dice. For example, if you roll 2 dice (6-sided), you're more likely to roll a 7 than anything else. You're least likely to roll a 2 or 12.

JASS:
function GetNormalRandomInt takes integer lower, integer higher returns integer
    local real deltaHalf = (higher - lower) / 2
    return lower + GetRandomInt(0, deltaHalf) + GetRandomInt(0, deltaHalf)
endfunction

GetNormalRandomInt(0, 100) would be most likely to return 50, with 49 and 51 being less likely, and 0 and 100 being least likely. It should be relatively straight forward to adapt this function so it is centered around a different number.

Yes this is exactly what I need! you can tell i completely bombed intro to stats lol.

i'm not familiar with jass, could I replace 100 with udg_Int? and it will pull the value of the Int global and set it as the peak value? also where is the output value from that ending up?
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
All right, here's a full solution.

input 1, then 1 is more likely than 2 which is more likely than 3...
input 20 then 5 is more likely than 4 which is more likely than 3... & 5 is more likely than 6 which is more likely than 7...
input 50 then 10 is more likely than numbers above and below it, with chances for the further numbers becoming less and less likely

So you first have to initialize an array that maps inputs to the value you want to be most likely.

  • InitializeItems
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set inputCenter[1] = 1
      • Set inputCenter[20] = 5
      • Set inputCenter[50] = 10
Here's the jass function you will want to use.
JASS:
function GetNormalRandomInt takes integer center returns integer
    local integer delta = IMaxBJ(center, 100 - center)
    local integer deltaHalf = delta / 2
    local integer lower = 100 - delta
    local integer rnd
    loop
        set rnd = lower + GetRandomInt(-deltaHalf, deltaHalf) + GetRandomInt(-deltaHalf, deltaHalf)
        if (rnd >= 0 and rnd <= 100) then
            return rnd
        endif
    endloop
    return 0
endfunction

Here's how to use it
  • Custom script: set udg_result = GetNormalRandomInt( udg_inputCenter[1] )
  • -------- the variable <result> is now a number between 0 and 100, most likely being 1 --------
  • Custom script: set udg_result = GetNormalRandomInt( udg_inputCenter[20] )
  • -------- the variable <result> is now a number between 0 and 100, most likely being 5 --------
  • Custom script: set udg_result = GetNormalRandomInt( udg_inputCenter[50] )
  • -------- the variable <result> is now a number between 0 and 100, most likely being 10 --------
 
Level 6
Joined
Jan 8, 2009
Messages
140
All right, here's a full solution.



So you first have to initialize an array that maps inputs to the value you want to be most likely.

  • InitializeItems
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set inputCenter[1] = 1
      • Set inputCenter[20] = 5
      • Set inputCenter[50] = 10
Here's the jass function you will want to use.
JASS:
function GetNormalRandomInt takes integer center returns integer
    local integer delta = IMaxBJ(center, 100 - center)
    local integer deltaHalf = delta / 2
    local integer lower = 100 - delta
    local integer rnd
    loop
        set rnd = lower + GetRandomInt(-deltaHalf, deltaHalf) + GetRandomInt(-deltaHalf, deltaHalf)
        if (rnd >= 0 and rnd <= 100) then
            return rnd
        endif
    endloop
    return 0
endfunction

Here's how to use it
  • Custom script: set udg_result = GetNormalRandomInt( udg_inputCenter[1] )
  • -------- the variable <result> is now a number between 0 and 100, most likely being 1 --------
  • Custom script: set udg_result = GetNormalRandomInt( udg_inputCenter[20] )
  • -------- the variable <result> is now a number between 0 and 100, most likely being 5 --------
  • Custom script: set udg_result = GetNormalRandomInt( udg_inputCenter[50] )
  • -------- the variable <result> is now a number between 0 and 100, most likely being 10 --------
I'm still slightly confused sorry. I want the max result to be 30, do I change the 100's in the jass to 30? also I want the centre value to be based off a skill level up to 100, so 100 means 30 is the centre, 1 means 1 is the centre.
I'm a little confused about initialising the centre values mostly.

for grabbing the code would set udg_result = GetNormalRandomInt( udg_inputCenter[myint] ) work?

EDIT2: okay i think I get it actually, to initialise the values would it be something along the lines of set centre[1] = 1, set centre[4] = 2, set centre[7] = 3... set centre[95] = 28, set centre[98] = 30
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
Well I'm quite confused too.
Here, I've rewritten the function to be more customizable.

JASS:
function GetNormalRandomInt takes integer lower, integer upper, integer center returns integer
    local integer delta = IMaxBJ(center - lower, upper - center)
    local integer deltaHalf = delta / 2
    local integer minimum = upper - delta
    local integer rnd
    loop
        set rnd = minimum + GetRandomInt(-deltaHalf, deltaHalf) + GetRandomInt(-deltaHalf, deltaHalf)
        if (rnd >= lower) then
            return rnd
        endif
    endloop
    return lower
endfunction

How to use it:
  • set udg_result = GetNormalRandomInt(0, 100, 30)
The GUI variable <result> will now contain a random integer between 0 and 100, with 30 being the most likely number. Simply replace the numbers with whatever you'd like. You can use Integer variables instead of numbers if you wish.

Let's say you want to generate a random number between 10 and 30, with a GUI variable <center> being most likely:
  • set udg_result = GetNormalRandomInt(10, 30, udg_center)
 
Level 6
Joined
Jan 8, 2009
Messages
140
Well I'm quite confused too.
Here, I've rewritten the function to be more customizable.

JASS:
function GetNormalRandomInt takes integer lower, integer upper, integer center returns integer
    local integer delta = IMaxBJ(center - lower, upper - center)
    local integer deltaHalf = delta / 2
    local integer minimum = upper - delta
    local integer rnd
    loop
        set rnd = minimum + GetRandomInt(-deltaHalf, deltaHalf) + GetRandomInt(-deltaHalf, deltaHalf)
        if (rnd >= lower) then
            return rnd
        endif
    endloop
    return lower
endfunction

How to use it:
  • set udg_result = GetNormalRandomInt(0, 100, 30)
The GUI variable <result> will now contain a random integer between 0 and 100, with 30 being the most likely number. Simply replace the numbers with whatever you'd like. You can use Integer variables instead of numbers if you wish.

Let's say you want to generate a random number between 10 and 30, with a GUI variable <center> being most likely:
  • set udg_result = GetNormalRandomInt(10, 30, udg_center)

set udg_result = GetNormalRandomInt(10, 30, udg_center)

that's the line!

do I need something to make this code work? pasting it as a trigger gives an error about needing inittrig or something?
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
I've attached a test map to make things easier. Test the map and enter "random" in chat to test 1000 random numbers.
If you're using World Edit NewGen, InitTrig shouldn't be a problem. Otherwise, try copying the jass code to the top-most section of the trigger editor, where the name of your map is displayed.
 

Attachments

  • temp.w3x
    17.4 KB · Views: 72
Level 6
Joined
Jan 8, 2009
Messages
140
it seems that no matter what I set the centre value it seems as if it's beginning from the bottom. forgive me if i've misunderstood how this should work but if i set the trigger to

  • Custom script: set udg_temp = GetNormalRandomInt(0, 20, 20, 5)
should 20 be the highest percent? it's displaying it as 0 every time.
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
Looks like a bug on my end. Try this:

JASS:
function GetNormalRandomInt takes integer lower, integer upper, integer center, integer iterations returns integer
    local integer delta = IMaxBJ(center - lower, upper - center)
    local integer deltaFraction = delta / iterations
    local integer random
	local integer iteration
    
    loop
		set iteration = 0
		set random = center
		loop
			set random = random + GetRandomInt(-deltaFraction, deltaFraction)
			set iteration = iteration + 1
			exitwhen iteration >= iterations
		endloop

        if (random >= lower and random <= upper) then
            return random
        endif
    endloop
    return lower
endfunction

Attached demomap now takes a <center> as an argument (e.g. "random 5" will generate random number between 0 and 20 centered around 5)
 

Attachments

  • temp.w3x
    17.6 KB · Views: 58
Level 6
Joined
Jan 8, 2009
Messages
140
Looks like a bug on my end. Try this:

JASS:
function GetNormalRandomInt takes integer lower, integer upper, integer center, integer iterations returns integer
    local integer delta = IMaxBJ(center - lower, upper - center)
    local integer deltaFraction = delta / iterations
    local integer random
	local integer iteration
    
    loop
		set iteration = 0
		set random = center
		loop
			set random = random + GetRandomInt(-deltaFraction, deltaFraction)
			set iteration = iteration + 1
			exitwhen iteration >= iterations
		endloop

        if (random >= lower and random <= upper) then
            return random
        endif
    endloop
    return lower
endfunction

Attached demomap now takes a <center> as an argument (e.g. "random 5" will generate random number between 0 and 20 centered around 5)

brilliant. absolutely brilliant. thankyou for sticking with me and my limited knowledge of jass lol. if i could rep you a hundred times over i would.

one thing, does the iteration value increase the height of the curve? if not what's it actually doing?
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
The iteration value will increase the height of the curve.
The basic idea behind the function is adding together multiple random numbers, as if you're rolling multiple dice.
Let's say iterations = 3 and you want to generate a random number between 3 and 30. You do so by rolling 3 ten-sided dice and adding the results together. The only combination to roll a 3 is by rolling 3x a one, thus your chance to roll a 3 is 0.1%. However, rolling a 15 can be done in various ways: you could roll 1 + 4 + 10, or 2 + 6 + 7. You get the idea, rolling a 15 will be much more common than rolling a 3 or 30. My function builds on the basic idea and simply moves the curve so it's centered around a different value.
Think of the "iterations" as the number of dice you're rolling. More dice = a steeper curve. You can get an idea of how the curve for your probabilities will look like here: http://anydice.com/

u should get rid of the BJ.
No I shouldn't. Not all BJ's are bad, and I don't think it's worth getting rid of this one at the cost of readability. The function will likely be called at most once every time a unit dies, so who cares.
 
Status
Not open for further replies.
Top