0

I have this kind of program structure for choosing at random program execution. However this style is not extendable, maintainable and very error prone. as you can see the condition of the if statements are getting long and unreadable

Can you suggest a better programming style / structure ?

double aProb = 0.4;

double bProb = 0.2;

double cProb = 0.2;

double dProb = 0.2;

double chance = random.nextDouble();

if ( chance < aProb ) {
    a();
}

if ( chance < bProb + aProb ) {
    b();
}

if ( chance < cProb + bProb + aProb ) {
    c();
}

if ( chance < dProb + cProb + bProb + aProb ) {
    d();
}
dmc
  • 401
  • 4
  • 14
  • 1
    how about....arrays! And, if you want to go overboard, possibly prefix sums (maybe fenwick trees). – keyser Jul 10 '14 at 17:46
  • a little code sample ? – dmc Jul 10 '14 at 17:47
  • accumulate the value by stepping through the array of probabilities. `currentProb += probs[i]`. I have no better way of attaching functions to this since function pointers don't really exist in java. – keyser Jul 10 '14 at 17:56

3 Answers3

1

I think it's clear.

If you want shorter,

double chance = random.nextDouble();

if ((chance -= 0.4) < 0) {
    a();
} else if ((chance -= 0.2) < 0) {
    b();
} else if ((chance -= 0.2) < 0) {
    c();
} else {
    d();
}

(I assume you wanted else if.)

Paul Draper
  • 78,542
  • 46
  • 206
  • 285
0

You could make a new variable storing aProb + bProb as that is used in every if statement except the first one, which would make it shorter.

Michael Barz
  • 276
  • 2
  • 11
0

You may create class abstract class IntervalAction:

public abstract class IntervalAction {

    private final double minBound;
    private final double maxBound;

    public IntervalAction(double minBound, double maxBound) {
        if (minBound < 0) throw new IllegalArgumentException("minBound >= 0");
        if (maxBound > 1) throw new IllegalArgumentException("maxBound <= 0");
        if (minBound > maxBound) throw new IllegalArgumentException("maxBound >= minBound");

        this.minBound = minBound;
        this.maxBound = maxBound;
    }

    public abstract void execute();

    @Override
    public String toString() {
        return "IntervalAction{" +
                "minBound=" + minBound +
                ", maxBound=" + maxBound +
                '}';
    }
}

and registry class which will have all available actions:

public class ActionRegistry {

    public void register(IntervalAction action) {
        if (intersectsWithExistingRange(action))
            throw new IllegalArgumentException("Already have action in that range: " + action);

        // todo registration in internal data structure
    }

    private boolean intersectsWithExistingRange(IntervalAction action) {
        // todo
        return true;
    }

    public void execute(double input) {
        IntervalAction action = find(input);
        if (action == null) throw new IllegalArgumentException("No action found for " + input);
        action.execute();
    }

    private IntervalAction find(double input) {
        // todo
        return null;
    }
}

And a driver class:

public class ActionDriver {
    private final ActionRegistry registry;
    private final Random random;


    public ActionDriver() {
        random = new Random(System.currentTimeMillis());

        registry = new ActionRegistry();
        registry.register(new IntervalAction(0, 0.1) {
            @Override
            public void execute() {
                System.out.println(this);
            }
        });
        registry.register(new IntervalAction(0.1, 0.2) {
            @Override
            public void execute() {
                System.out.println(this);
            }
        });
        // so on
    }


    public void act() {
        registry.execute(random.nextDouble());
    }
}

Now, the most interesting part is how can you implement internal data structure in ActionRegistry to hold (and search for) your actions -- all of these todos in above code sample. For that I'll refer you to this SO question.

Community
  • 1
  • 1
Victor Sorokin
  • 11,878
  • 2
  • 35
  • 51
  • 1
    @PaulDraper don't be sad. There are easier ways to do this using Java like `TreeSet`, or even better, `TreeSet` instead. – Luiggi Mendoza Jul 10 '14 at 19:21
  • @LuiggiMendoza I think `Map` is a better suit for this, as there's link between an interval and an action in OP question. And SO question I've linked uses exactly `Map`. – Victor Sorokin Jul 10 '14 at 19:33
  • @VictorSorokin then you should have voted to close this question as a duplicate... – Luiggi Mendoza Jul 10 '14 at 19:34
  • @LuiggiMendoza IMHO, it's not a duplicate, since this question is primary about "code desing" for the given task, whereas linked question is about implementation detail. – Victor Sorokin Jul 10 '14 at 19:36