1
\$\begingroup\$

(See the previous iteration.)

This time, I removed the stuff I don't need in my demo runner. Also, I consolidated some code that seemed DRY to me.

Simulation rules

  1. When a female arrives, she ensures that the seat is down before performing the urge. She leaves the seat down before exiting.
  2. When a male arrives to pee, he makes sure the seat is up and pees. After peeing, if we require all the visitors to put down the seat, the male puts it down. Otherwise, the seat remains upwards.
  3. When a male arrives to poo, the case 1 applies.

Here it goes:

package com.github.coderodde.simulation.toiletseat;

import java.util.Random;

public final class ToiletSeatSimulator {

    private static enum Gender {
        FEMALE,
        MALE,
    }

    private static enum Operation {
        PEE,
        POOP,
    }

    private static enum SeatPosition {
        UP,
        DOWN,
    }

    private final int queueLength;
    private final double femaleRatio;
    private final double peeRatio;
    private final boolean alwaysLeaveSeatDown;
    private final Random random;
    private SeatPosition seatPosition = SeatPosition.DOWN;
    private int movements = 0;

    public ToiletSeatSimulator(int queueLength, 
                               double femaileProportion, 
                               double urinationProportion,
                               boolean alwaysLeaveSeatDown,
                               Random random) {
        this.queueLength = queueLength;
        this.femaleRatio = femaileProportion;
        this.peeRatio = urinationProportion;
        this.alwaysLeaveSeatDown = alwaysLeaveSeatDown;
        this.random = random;
    }

    public int simulate() {
        for (int i = 0; i < queueLength; i++) {
            performOperation(getRandomGender(), 
                             getRandomOperation());
        }

        return movements;
    }

    private void performOperation(Gender gender, Operation operation) {
        switch (operation) {
            case POOP: 
                setSeatPosition(SeatPosition.DOWN);
                return;

            case PEE:
                switch (gender) {
                    case FEMALE:
                        setSeatPosition(SeatPosition.DOWN);
                        return;

                    case MALE:
                        setSeatPosition(SeatPosition.UP);

                        if (alwaysLeaveSeatDown) {
                            setSeatPosition(SeatPosition.DOWN);
                        }

                        return;
                }
        }
    }

    private void setSeatPosition(SeatPosition seatPosition) {
        if (this.seatPosition != seatPosition) {
            this.seatPosition = seatPosition;
            movements++;
        }
    }

    private Gender getRandomGender() {
        double coin = random.nextDouble(); // In the range [0, 1).
        return coin < femaleRatio ? Gender.FEMALE : Gender.MALE;
    }

    private Operation getRandomOperation() {
        double coin = random.nextDouble();
        return coin < peeRatio ? Operation.PEE : Operation.POOP;
    }
}

... and the demo driver is:

package com.github.coderodde.simulation.toiletseat;

import java.util.Random;

public final class Demo {

    private static final int QUEUE_LENGTH = 1000;
    private static final double FEMALE_RATIO = 0.55;
    private static final double PEE_RATIO = 0.9;

    public static void main(String[] args) {
        long seed = System.currentTimeMillis();
        System.out.println("<<< Seed = " + seed + " >>>");

        Random random1 = new Random(seed);
        Random random2 = new Random(seed);

        ToiletSeatSimulator simulator1 = 
                new ToiletSeatSimulator(
                        QUEUE_LENGTH, 
                        FEMALE_RATIO,
                        PEE_RATIO,
                        false,
                        random1);

        System.out.println(
                "Number of seat moves when changing seat position " 
                        + "on demand: " 
                        + simulator1.simulate());

        ToiletSeatSimulator simulator2 = 
                new ToiletSeatSimulator(
                        QUEUE_LENGTH, 
                        FEMALE_RATIO,
                        PEE_RATIO,
                        true,
                        random2);

        System.out.println(
                "Number of seat moves when changing seat position back to " 
                        + "closed: " 
                        + simulator2.simulate());
    }
}

Critique request

Now, what do you think? Did I improve anything?

\$\endgroup\$
1
  • 4
    \$\begingroup\$ Possible typo: femaileProportion. Or is a femaile some kind of email by a female? \$\endgroup\$ Commented Oct 28, 2022 at 13:26

1 Answer 1

3
\$\begingroup\$
    private void performOperation(Gender gender, Operation operation) {
        switch (operation) {
            case POOP: 
                setSeatPosition(SeatPosition.DOWN);
                return;

            case PEE:
                switch (gender) {
                    case FEMALE:
                        setSeatPosition(SeatPosition.DOWN);
                        return;

                    case MALE:
                        setSeatPosition(SeatPosition.UP);

                        if (alwaysLeaveSeatDown) {
                            setSeatPosition(SeatPosition.DOWN);
                        }

                        return;
                }
        }
    }

This could be written more briefly:

    private void performOperation(PositionPreference preference, Operation operation) {
        switch (preference) {
            case STANDER:
                if (operation == PEE) {
                    setSeatPosition(SeatPosition.UP);

                    if (leaveSeatAsUsed) {
                        return;
                    }
                }
            case SITTER:
                setSeatPosition(SeatPosition.DOWN);
                return;

        }
    }

or even more briefly without the switch (may also be more readable and maintainable)

    private void performOperation(PositionPreference preference, Operation operation) {
        if ((preference == STANDER) && (operation == PEE)) {
            setSeatPosition(SeatPosition.UP);

            if (leaveSeatAsUsed) {
                return;
            }
        }

        setSeatPosition(SeatPosition.DOWN);
    }

Either has exactly the same behavior as the original but only uses two setSeatPosition calls rather than four. We now cover three situations with one case:

  1. Person is a SITTER.
  2. Person is performing a non-PEE operation.
  3. Person is a STANDER who performed a PEE operation with leaveSeatAsUsed false.

Changing to leaveSeatAsUsed may be clearer about what the variable does. Also, this way, we only use the variable to prevent the default behavior. Otherwise, we can fall through to the next case.

We don't need Gender (actually the wrong term here; sex would be more relevant). A PositionPreference gives us all the relevant information without making any assumptions about gender or sex.

If the person is a SITTER, we don't care about the Operation. Such people always put the seat down.

Obviously, other names should change outside this block of code for consistency.

\$\endgroup\$
3
  • \$\begingroup\$ You switch for STANDER is cool, no break needed. Kudos! \$\endgroup\$
    – coderodde
    Commented Oct 30, 2022 at 5:54
  • 2
    \$\begingroup\$ Having a switch without break dangerously leads to misinterpretation of the code, and makes the code less maintainable. I like the suggestion of PositionPreference over Gender, though. It makes no assumption on sex nor gender \$\endgroup\$ Commented Oct 30, 2022 at 7:21
  • \$\begingroup\$ Side note: No need for the extra parenthesis in if ((preference == STANDER) && (operation == PEE)) {. This would be enough: if (preference == STANDER && operation == PEE) { \$\endgroup\$ Commented Oct 31, 2022 at 12:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.