0

I'm really used to writing if statements for two different events, which could be best outlined by the following pseudocode:

double random = Math.random();
if(random<0.5) event A;
else event B;

But when there's more than 2 different events (let's say 4 in this instance) with different probabilities, the only thing I've found is the following, but it seems way too verbose for the simple thing I'm trying to achieve, there has to be a much simpler way to do this, right?

double random = Math.random();
if(random<0.3) event A;
else if(random>=0.3 && random<0.5) event B;
else if (random>=0.5 && random<0.8) event C;
else event D;

Clearly there's a better algorithm to do this?

Nihilish
  • 105
  • 1
  • 16

5 Answers5

2

When you get to the first else if, your random variable has already been checked against 0.3. You don't have to check again. Same with the other conditional checks you're doing. You've already ruled out the ranges of values to the left of each &&. Try this.

double random = Math.random();
if(random<0.3) event A;
else if(random<0.5) event B;
else if (random<0.8) event C;
else event D;
mypetlion
  • 2,415
  • 5
  • 18
  • 22
  • 1
    The only worry here is that now the `if` statements are order-dependent. Probably a moot point though – flakes Jan 05 '18 at 22:09
1

You can use Arrays.binarySearch to determine which event to happen. the -index - 1 is the insert position. Then you can use switch to choose events rather than handle error-prone if else statement. You can also use the event as index for something.

// event 0 [0.0, 0.2] 20% 
// event 1 (0.2, 0.5] 30%
// event 2 (0.5, 0.8] 30%
// event 3 (0.8, 1.0] 20%
double[] chance = {0.2, 0.5, 0.8, 1};
int event = Arrays.binarySearch(chance, Math.random());
if (event < 0) event = -event - 1;
switch (event) {
    case 0:
        // event 0
        break;
    case 1:
        // event 1
        break;
    case 2:
        // event 2
        break;
    case 3:
        // event 3
        break;
}
Zoe
  • 27,060
  • 21
  • 118
  • 148
zhh
  • 2,346
  • 1
  • 11
  • 22
0

There are a few ways,you can also use switch case (and i think it is way better for a lot of cases) If you are creative you can use data structures for something that goes like this( for example):

Pair p= new Pair<Integer,Integer>;
Map<Event eventA,Pair P> newMap =...
double random = Math.random();
for(Map.Entry<Integer,Integer> pair: newMap){
   if(pair.getPair().between(random)){
     return pair.getEvent();
     }
 }

You make a map of Events as keys and Pairs of Integers as values. for each pair you check if the random number is between his values (of course, you'll have to implement it, but it's not a big deal), and if it is, then just return that Event (or Execute it) The small details are not a huge deal here, i have just showed a way of thinking that i would be doing this if it there were a lot of 'if' (if you don't want to think how to implement the Event thing, you can throw the map away, make list of pairs, for each pair check if in between and return a number, and in switch case [of numbers,much more elegant] just do something for each number)

I can think of lots of ways to do it, try to think creatively :)

Or251
  • 196
  • 10
0

You can implement an array of probabilities from 0 to 100 (or 0.0 to 1.0).

The array will have as many elements as the number of events.

//For example of 4 events:

//Event A: 30% chance
//Event B: 15% chance
//Event C: 20% chance
//Event D: 35% chance

int[] chances = {30, 45, 65, 100};

To get the event based on their respective probabilities:

public int getEventIdx(){
    int idx = 0, r = rnd.nextInt(100);
    for(int i=0; i<chances.length-1; i++)
        if(r > chances[i])
            idx++;
    return idx;
}

You can have a parallel array of Events:

MyEvent events[4] = {...};             //where ... are the events
events[getEventIdx()].triggerEvent();  //run event base on probability

You can have a method like triggeerEvent in your MyEvent objects which contains all the things you want to do for that particular event.

Other than using parallel arrays, using other data structures such as map is also possible.

user3437460
  • 17,253
  • 15
  • 58
  • 106
-1

Two ways I sometimes use:

public String chooseRandomString() {
    String[] possibilities = new String[] { "Case A", "Case B", "Case C" };
    return possibilities[(int) (Math.random() * possibilities.length)];
}

public void chooseRandomCase() {
    int caseID = (int) (Math.random() * 3);

    switch (caseID) {
    case 0:
        // do something ...
        break;
    case 1:
        // do something ...
        break;
    case 2:
        // do something ...
        break;
    default:
        break;
    }
}
Feirell
  • 719
  • 9
  • 26
  • This assumes you want each event to have equal weighting – flakes Jan 05 '18 at 22:08
  • @flakes that is not necessarily true, you could use some mathematical function to weight the outcomes, but this is for sure not the best way if you have not an equal distribution. – Feirell Jan 05 '18 at 22:12