Using random chance with more than two potential outcomes

michaelsahn
11 Feb 2014, 22:26
I'd like to randomly display one of three messages when the player enters a room. I'm using Random Chance to set percentage, but I'm unsure of how to do this with three potential outcomes.

This is how I'm doing it for two potential outcomes:

if (RandomChance(50)) {
msg ("test1")
}
else {
msg ("text2")
}


How do I do this for three or more potential outcomes? I've search forum, wiki and library for answers/examples but perhaps this is too simple a question to be addressed!

Thanks -

Mike

HegemonKhan
12 Feb 2014, 03:14
quick note:

"if (RandomChance (Value))" is the exact same thing (though it's a shortened, ie quest-code-understood, form of) "if (RandomChance (Value) = true)"

this is the same thing for Boolean Attributes:

"Object.visible" is the same as "Object.visible=true"

if you don't put the "=false", then it's understood to be "=true", by the quest engine

(I just like to write it out in full, for new people, and myself too, to see it correctly, to avoid any confusion that they, or me, may have, lol)

-----------------------

"RandomChance" is for, using an analogy, '1/1,000,000,000,000 chance of winning the lottery' = % chance of just a single choice being true (of occuring, ie 'winning')

example:

in a shuffled deck of cards, the chance of the top card being an Ace of Spades = whatever you set the percent "Value (0 through 100)" to in "RandomChance (Value)", you SET~DECIDE the ODDS of that single 'card' (choice~option~selection).

if (RandomChance (100) = true) {
-> // whatever script_1
} else {
-> // whatever script_2
}
// script_1 will always be executed, lol

if (RandomChance (99) = true) {
-> // whatever script_1
} else {
-> if (RandomChance (100) = true) {
->-> // whatever script_2
-> }
}
// there's a 99% chance that script_1 will be executed, but should the "1%" happen (lol), then there's a 100% chance that script_2 will be executed

if (RandomChance (99) = true) {
-> // whatever script_1
} else {
-> if (RandomChance (50) = true) {
->-> // whatever script_2
-> }
}
// there's a 99% chance that script_1 will be executed, but should the "1%" happen (lol), then there's a 50% chance that script_2 will be executed

if (RandomChance (99) = true) {
-> // whatever script_1
} else {
-> if (RandomChance (0) = true) {
->-> // whatever script_2
-> }
}
// there's a 99% chance that script_1 will be executed, and despite should the "1%" happen (lol), script_2 will *NEVER* be executed anyways

if (RandomChance (100) = true) {
-> // whatever script_1
} else {
-> if (RandomChance (100) = true) {
->-> // whatever script_2
-> }
}
// there's a 100% chance that script_1 will be executed, so despite script_2 having a 100% chance of executing, it will *NEVER* be executed because it never makes it to that code line, as it requires the *failure* of script_1 to be executed, but at 100% chance of success, there's 0% chance of failure, lol.

----

and we can make it include more than 2 choices~options~selections, too:

(the "50" Value has nothing to do with this, you can change each of the three "50s" to any Value between 0 and 100, though 0 and 100 will possibly wipe out parts of your scripting as I've shown already above, hopefully)

CONCEPTUALLY:

if (RandomChance (50) = true) {
-> // whatever script_1
} else {
-> if (RandomChance (50) = true) {
->-> // whatever script_2
-> } else {
->-> if (RandomChance (50) = true) {
->->-> // whatever script_3
->-> }
-> }
}

CORRECT SYNTAX~FORMAT:

if (RandomChance (50) = true) {
-> // whatever script_1
} else if (RandomChance (50) = true) {
-> // whatever script_2
} else if (RandomChance (50) = true) {
-> // whatever script_3
}

and if you want full functionality:

(I'm changing the Values to make it more clear for you)

// also, you need to understand this too about how RandomChance actually works:
// if (true_a=true_b), then do this_1
// if (false_a=true_b), then (CAN'T) do this_1
// if (false_a=false_b), then do this_2
// if (true_a=false_b), then (CAN'T) do this_2
// true_a = successful RandomChance (Value), otherwise if it fails, then it equals (returns): false_a
// for the "true_b" or "false_b", you type in what you want: "=true" or "=false"
//
// this probably just confused you... so let me give examples:
//
// if (RandomChance (100) = true)
// if (100% chance of being true = true)
// 100% chance of being true, means that it always RETURNS (or IS): true
// we thus (conceptually are) algebraically substituting out "RandomChance (100)" for placing in: "true"
// look at my colors of font to see this
// if (true = true), then do script
//
// if (RandomChance (50) = true)
// if (50% chance of being true = true)
// 50% chance of being true, means that it will 50% be "true" and 50% be "false", thus RETURNS (or IS): true (50%) or false (50%)
// we thus (conceptually are) algebraically substituting out "RandomChance (50)" for placing in: "true" (50%) or "false" (50%)
// look at my colors of font to see this
// if (true = true), then do script
// if (false = true), then (CAN'T) do script
//
// or another way of trying to explain it:
//
// if (RandomChance (100) = true) -> 100% SUCCESS (100% TRUE = true), it does script_1
// if (RandomChance (100) = false) -> 0% SUCCESS (100% TRUE -> 100% true = false -> ERROR!), it does NOT do script_1
//
// if (RandomChance (0) = true) -> 0% SUCCESS (0% TRUE -> 100% false = true OR 0% true = true -> ERROR!), it does NOT do script_1
// if (RandomChance (0) = false) -> 100% SUCCESS (0% TRUE -> 100% false = false), it does script_1
//
// if (RandomChance (50) = true) -> 50% SUCCESS (50% TRUE = true), it does script_1 only 50% of the time
// if (RandomChance (50) = true) -> 50% FAILURE (50% TRUE = true), it does script_1 only 50% of the time
//
// if (RandomChance (50) = false) -> 50% SUCCESS (50% TRUE -> 50% false = false), it does script_1 only 50% of the time
// if (RandomChance (50) = false) -> 50% FAILURE (50% TRUE -> 50% true = false), it does script_1 only 50% of the time
//
// if (RandomChance (75) = true) -> 75% SUCCESS (75% TRUE -> 75% true = true), it does script_1 only 75% of the time
// if (RandomChance (75) = false) -> 25% SUCCESS (75% TRUE -> 25% false = false), it does script_1 only 25% of the time
//
// if (RandomChance (25) = true) -> 25% SUCCESS (25% TRUE -> 25% true = true), it does script_1 only 25% of the time
// if (RandomChance (25) = false) -> 75% SUCCESS (25% TRUE -> 75% false = false), it does script_1 only 75% of the time

if (RandomChance (75) = true) {
-> // whatever script_1a
} else if (RandomChance (75) = false) {
-> // whatever script_1b
} else if (RandomChance (90) = true) {
-> // whatever script_2a
} else if (RandomChance (90) = false) {
-> // whatever script_2b
} else if (RandomChance (60) = true) {
-> // whatever script_3a
} else if (RandomChance (60) = false) {
-> // whatever script_3b
}

------------------

whereas, "GetRandomInt", is for, using an analogy, 'selection out of a collection of choices, such as playing rock paper scissors game' = the selection alogrithm of~for some number of choices

example:

in a shuffled deck of cards, the chance of the top card being an Ace of Spades = 1/52 odds + the algorithm (that is used by "GetRandomInt") the computer (well, quest, anyways) uses to determine what card will be at the top, which gets turned over.

(actual) example:

selection = ToString (GetRandomInt (1,3))
if (selection = "1") {
-> // script_1
} else if (selection = "2") {
-> // script_2
} else if (selection = "3") {
-> // script_3
}

~OR~

selection = ToString (GetRandomInt (1,3))
switch (selection) {
-> case ("1") {
->-> // script_1
-> }
-> case ("2") {
->-> // script_2
-> }
-> case ("3") {
->-> // script_3
-> }

Liam315
12 Feb 2014, 03:15
There are a couple of ways to do it:

1. Using the random chance element of the if/else statements like you have already.

This requires a bit of mathematical calculation on your part to make the chance of each outcome equal. For 3 possibilities it would look like this-

if (RandomChance(33)) {
msg ("text1")
}
else if (RandomChance(50)) {
msg ("text2")
}
else {
msg ("text3")
}


When the code is run, there is a 1 in 3 chance that text1 will be printed, which is what you want because there are 3 possibilities of even chance. If it returns false (2 in every 3 times) there are 2 possibilities remaining, so to maintain an even chance on both the number has to be increased to 50. Obviously this becomes more complicated the more possibilities you have, or if you want to introduce uneven chances.


2. Using the GetRandomInt function- this is probably the better choice.
http://quest5.net/wiki/GetRandomInt

Your code would look something like this:

outcome = GetRandomInt(1,3)
if (outcome = 1) {
msg ("text1")
}
else if (outcome = 2) {
msg ("text2")
}
else {
msg ("text3")


The benefits of doing things this way is that a) the likelihood of generating any number in your specified range is equal and you don't need to calculate anything, and b) you can then more easily allow for unequal outcome chances by using ranges of numbers in your if/else statements.

michaelsahn
12 Feb 2014, 03:32
Thanks for your replies - I now know how to use GetRandomInt - it will come in handy!

-Mike

HegemonKhan
12 Feb 2014, 03:57
if you can understand using lists~dictionaries (not easy for new people), then it'll look like this:

lists~dictionaries start from 0, not from 1
lists~dictionaries are ordered, if horizontal: from left to right (or if vertical: from up to down)

split ("red;blue;yellow",";")

choice 0: red
choice 1: blue
choice 2: yellow

list_choices = split ("red;blue;yellow",";")
selection = StringListItem (list_choices, GetRandomInt (0,2))
// let's say "GetRandomInt" selects "1"
msg (selection)
// outputs: blue

list_choices = split ("red;blue;yellow",";")
selection = StringListItem (list_choices, GetRandomInt (0,2))
// let's say "GetRandomInt" selects "0"
msg (selection)
// outputs: red

list_choices = split ("red;blue;yellow",";")
selection = StringListItem (list_choices, GetRandomInt (0,2))
// let's say "GetRandomInt" selects "2"
msg (selection)
// outputs: yellow

-------

examples for (STRING) dictionaries:

Key = Value
(string_1 = string_2)

split ("1=red;2=blue;3=yellow",";")

choice 1: red
choice 2: blue
choice 3: yellow

-------
the ordering however is:

0: red
1: blue
2: yellow

but we are *NOT* using ordering in this case with the dictionary, as we're using the match up of its "key" to the "GetRandomInt" selection Value
-------

dictionary_choices = split ("1=red;2=blue;3=yellow",";")
selection = StringDictionaryItem (dictionary_choices, ToString (GetRandomInt (1,3)))
// let's say "GetRandomInt" selects "2"
msg (selection)
// outputs: blue

dictionary_choices = split ("1=red;2=blue;3=yellow",";")
selection = StringDictionaryItem (dictionary_choices, ToString (GetRandomInt (1,3)))
// let's say "GetRandomInt" selects "1"
msg (selection)
// outputs: red

dictionary_choices = split ("1=red;2=blue;3=yellow",";")
selection = StringDictionaryItem (dictionary_choices, ToString (GetRandomInt (1,3)))
// let's say "GetRandomInt" selects "3"
msg (selection)
// outputs: yellow

HegemonKhan
12 Feb 2014, 04:41
GetRandomInt = The ODDS via merely the number of choices~options listed and plus the alogorithm used for its "random" selection of one of those choices~selections:

choices~options: 1,2,3 (range: 1-3)
thus the ODDS are: 33% (1/3), however...
also, its algorithm then decides whether to actually pick: 1, 2, or 3 ... for its "randomness".

you can see~play~test~examine~research it via my test "game", lol:

viewtopic.php?f=5&t=4094

----------

RandomChance = your own custom-decided (your own inputed ~ code-typed-in) ODDS foreach (individual and totally inpendant) choice~option

but you'll need additional scripting to move from calculating~determining what to do for one choice~option to the next choice~option, unless you use that fancy math-method with RandomChance that Liam showed in his post, though you still need some extra~correct scripting still to move from one choice~option to the next choice~option.

if~when you move to more complicated stuff (such as combat~damage or whatever RPG aspect), this seems to work well (in the limited, hardly any, testing of it that I've done so far, lol):

RandomChance (Object_1.Integer_Attribute_1 - Object_2.Integer_Attribute_1)
// obviously you need to make sure (ie check) that Object_1's attribute is equal or higher than Object_2's attribute

if (RandomChance (HK.dexterity - orc.agility) = true) {
// "dexterity" and "agility" are integer (int) attributes
-> msg ("You successfully hit the orc!")
} else {
-> msg ("You failed to hit the orc...")