3

I have an enum with some possible actions

internal enum Action
{
    Stay,
    MoveLeft,
    MoveRight
}

and an object holding information about the current chance for this action

internal class ActionWithPossibility
{
    public Action Action { get; }
    public int ActionChancePercent { get; }

    public ActionWithPossibility(Action action, int actionChancePercent)
    {
        Action = action;
        ActionChancePercent = actionChancePercent;
    }
}

the chance goes from 0 to 100. A collection of actions with their chance could be

        List<ActionWithPossibility> actionsWithPossibilities = new List<ActionWithPossibility>() {
            new ActionWithPossibility(Action.Stay, 40),
            new ActionWithPossibility(Action.MoveLeft, 30),
            new ActionWithPossibility(Action.MoveRight, 30)
        };

or

        List<ActionWithPossibility> actionsWithPossibilities = new List<ActionWithPossibility>() {
            new ActionWithPossibility(Action.Stay, 30),
            new ActionWithPossibility(Action.MoveLeft, 10),
            new ActionWithPossibility(Action.MoveRight, 60)
        };

or

        List<ActionWithPossibility> actionsWithPossibilities = new List<ActionWithPossibility>() {
            new ActionWithPossibility(Action.Stay, 30),
            new ActionWithPossibility(Action.MoveLeft, 60),
            new ActionWithPossibility(Action.MoveRight, 10)
        };

There are 2 important things:

  • The sum of the possibilities will be 100.
  • More or less actions are possible. So the amount of actions is unknown.

When calling a random action via this method

    public void NextAction(List<ActionWithPossibility> actionsWithPossibilities)
    {
        int randomNumber = random.Next(0, 100);

        // ...

        Action targetAction = null; // ?
    }

Is there a way to calculate the action (without using ifs)? I thought about this setup:

  • Action A 30
  • Action B 10
  • Action C 60

I could sum up the predecessors of the current action and would get this result

  • Action A 0 - 30
  • Action B 30 - 40
  • Action C rest

but I don't know how to calculate the action by code. Some help would be awesome.

This might be a possible duplicate of

Percentage Based Probability

but as I mentioned before the amount of possible actions is unknown so I can't go for three if statements. And maybe there is a trick using some math to avoid if statements completely.

  • Possible duplicate of [Percentage Based Probability](https://stackoverflow.com/questions/20430405/percentage-based-probability) – Sinatr Mar 14 '19 at 15:04
  • Use three if statements : if(randomNumber <= 30) {event one} else {if(randomnumber <=40) {event two } else { event three} – jdweng Mar 14 '19 at 15:07
  • I updated my question –  Mar 14 '19 at 15:16

2 Answers2

2
int threshold = 0;
int randomNumber = random.Next(0, 100);
for (var i = 0; i < actionsWithPossibilities.Count; i++)
{
    var item = actionsWithPossibilities[i];
    threshold += item.ActionChancePercent;

    if (randomNumber <= threshold)
    {
        //first action that's under the defined threshold is placed in result
        result = item.Action;
        break;
    }
}
NotFound
  • 5,005
  • 2
  • 13
  • 33
0

If you have your actions in a list and want to map the random number you generate to the correct object. You could think like:

LINQ:

actionsWithPossibilities
   .OrderBy(x => x.actionChancePercent) // Sort probabilities in increasing order
   .First(y => randomNumber <= y.actionChancePercent)
   // Find the correct 'bracket' by checking when the 
   // random number passes the thresholds.
Adam
  • 2,845
  • 2
  • 32
  • 46