(See also the next iteration.)
I have this small simulation program simulating a toilet seat. The toilet seat may be in two positions: up or down. If a male arrives to the toilet to urinate, and notices that it is down, he must put it upwards. What we are measuring, are two strategies:
- Each visitor leaves the seat in the same position as they used it.
- Each visitor puts the seat down.
My code follows:
package com.github.coderodde.simulation.toiletseat;
import java.util.Objects;
import java.util.Random;
public final class ToiletSeatSimulator {
private static final int MINIMUM_QUEUE_LENGTH = 1;
private static enum Gender {
FEMALE,
MALE,
}
private static enum Operation {
URINATE,
POOP,
}
private static enum ToiletSeatPosition {
UP,
DOWN,
}
private final int queueLength;
private final double femailProportion;
private final double urinationProportion;
private final boolean closeDown;
private final Random random;
private ToiletSeatPosition toiletSeatPosition;
private int seatsMoved = 0;
public ToiletSeatSimulator(int queueLength,
double femaileProportion,
double urinationProportion,
boolean closeDown,
Random random) {
this.queueLength = checkQueueLength(queueLength);
this.femailProportion = checkFemaleProportion(femaileProportion);
this.urinationProportion =
checkUrinationProportion(urinationProportion);
this.closeDown = closeDown;
this.random = Objects.requireNonNull(random, "The Random is null.");
this.toiletSeatPosition = ToiletSeatPosition.DOWN;
}
public int simulate() {
for (int i = 0; i < queueLength; i++) {
performOperation(getRandomGender(),
getRandomOperation());
}
return seatsMoved;
}
private void performOperation(Gender gender, Operation operation) {
switch (operation) {
case URINATE:
performUrination(gender);
break;
case POOP:
performPoop(gender);
break;
default:
throw new IllegalStateException(
"Unkwnown Gender enum: " + gender);
}
if (closeDown && toiletSeatPosition == ToiletSeatPosition.UP) {
toiletSeatPosition = ToiletSeatPosition.DOWN;
seatsMoved++;
}
}
private void performUrination(Gender gender) {
switch (gender) {
case FEMALE:
performFemaleUrination();
break;
case MALE:
performMaleUrination();
break;
default:
throw new IllegalStateException(
"Unknown Gender enum: " + gender);
}
}
private void performFemaleUrination() {
if (toiletSeatPosition == ToiletSeatPosition.UP) {
toiletSeatPosition = ToiletSeatPosition.DOWN;
seatsMoved++;
}
}
private void performMaleUrination() {
if (toiletSeatPosition == ToiletSeatPosition.DOWN) {
toiletSeatPosition = ToiletSeatPosition.UP;
seatsMoved++;
}
}
private void performPoop(Gender gender) {
switch (gender) {
case FEMALE:
performFemalePoop();
break;
case MALE:
performMalePoop();
break;
default:
throw new IllegalStateException(
"Unknown Gender enum: " + gender);
}
}
private void performFemalePoop() {
if (toiletSeatPosition == ToiletSeatPosition.UP) {
toiletSeatPosition = ToiletSeatPosition.DOWN;
seatsMoved++;
}
}
private void performMalePoop() {
if (toiletSeatPosition == ToiletSeatPosition.UP) {
toiletSeatPosition = ToiletSeatPosition.DOWN;
seatsMoved++;
}
}
private Gender getRandomGender() {
double coin = random.nextDouble(); // In the range [0, 1).
return coin < femailProportion ? Gender.FEMALE : Gender.MALE;
}
private Operation getRandomOperation() {
double coin = random.nextDouble();
return coin < urinationProportion ? Operation.URINATE : Operation.POOP;
}
private static int checkQueueLength(int queueLength) {
if (queueLength < MINIMUM_QUEUE_LENGTH) {
throw new IllegalArgumentException(
"Queue length is too small: "
+ queueLength
+ ". Must be at most "
+ MINIMUM_QUEUE_LENGTH
+ ".");
}
return queueLength;
}
private static double checkFemaleProportion(double femaleProportion) {
if (Double.isInfinite(femaleProportion)) {
throw new IllegalArgumentException(
"Female proportion is infinite in absolute value: "
+ femaleProportion);
}
if (Double.isNaN(femaleProportion)) {
throw new IllegalArgumentException("Female proportion is NaN.");
}
if (femaleProportion < 0.0 || femaleProportion > 1.0) {
throw new IllegalArgumentException(
"Female proportion is out of bounds: "
+ femaleProportion
+ ". Must be within closed range [0,1].");
}
return femaleProportion;
}
private static double checkUrinationProportion(double urinationProportion) {
if (Double.isInfinite(urinationProportion)) {
throw new IllegalArgumentException(
"Urination proportion is infinite in absolute value: "
+ urinationProportion);
}
if (Double.isNaN(urinationProportion)) {
throw new IllegalArgumentException("Urination proportion is NaN.");
}
if (urinationProportion < 0.0 || urinationProportion > 1.0) {
throw new IllegalArgumentException(
"Urination proportion is out of bounds: "
+ urinationProportion
+ ". Must be within closed range [0,1].");
}
return urinationProportion;
}
}
The demo follows:
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_PROPORTION = 0.55;
private static final double URINATION_PROPORTION = 0.2;
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_PROPORTION,
URINATION_PROPORTION,
false,
random1);
System.out.println(
"Number of seat moves when changing seat position "
+ "on demand: "
+ simulator1.simulate());
ToiletSeatSimulator simulator2 =
new ToiletSeatSimulator(
QUEUE_LENGTH,
FEMALE_PROPORTION,
URINATION_PROPORTION,
true,
random2);
System.out.println(
"Number of seat moves when changing seat position back to "
+ "closed: "
+ simulator2.simulate());
}
}
The typical output is:
<<< Seed = 1666884294029>>>
Number of seat moves when changing seat position on demand: 146
Number of seat moves when changing seat position back to closed: 162
Critique request
As always, I would like to hear any comments. Especially, I doubt the correctness of my implementation, since the above figures are rather optimistic to me.
ToiletSeatSimulator:: performOperation
throws"Unkwnown Gender enum: " + gender
? \$\endgroup\$