I am working on a video game where the enemy units need to be dispatched onto the screen at a regular interval, but must remain somewhat random. So lets say I need to put them onto the screen at a rate of 30 per minute.
Currently I randomly pick an integer between [1 - 100] every 600 ms. If the number is 30 or less, then a unit is dispatched. If the number is greater than 30, I do not dispatch the unit. Because there are 100 600 ms intervals within 60 seconds I do arrive at the goal of 30 units per minute.
The problem is that the distribution is not that even. Sometime there are periods of not many units being dispatched, and other times when there are too many.
Is there a way I can smooth out the distribution so that it remains randomish but allows for a more consistent flow of units?
EDIT: I followed @Ross Millikan 's advice and below are the results. Definitely a lot smoother using his algorithm.
3 units randomly distributed every 10 slots ___X___X_X___XXX_____X_____X_X______XX_X_X_____XX_X_X______X__X__XX____X____X__X_____XX_X____X_XX___X___X___X___X___X__X___X_X___X_____XX_X_X__XX______XXX_________X__X__X_____XX_X______X_XX___X_X___X_X___X_X____X_____XX__X_X_X________XXX_____X____X_X_X_X___X___X_X___X__X_X____X____XX_X_____XX_____X____X___XX______XX_X_X____X___X____X_X_X____X__X__X__X____XX__XX___X_______X__X_XX______X_X____X__X_X_X_X_X_____X___X__X____X___XX___X____X_XX_X___X___X_X______XX__X_X_____X______XX_X__X_X_________XX_X____X_X_X_XX___X_____X_X__X___X_____X__X_X_____XX_X_X_X_____X____X___XX__X_X_____X___X_X__X_X_X________XX___X_____X__XX__X__X__X____X__X___XX_______XXX_______XXX_X__X________X___XXX____XX_______X_X__X__XX____X__X__X____X_____XX_X_____X_XX___X__X___X___X_X_X____X__X____X__X__X__X_X___XX______X___XX______X_XX____XX_____X_X____XX__X_X____X__XX___X_____X___X__X___X__X_X__X___XX____X___X_X_____X____XX_X______X_XX__X_____X_X______XX___X_X___XX_____XX__X__X_____X___X_X__X___X_XX____X_____XX__XXX_______
30 out of 100 chance of a unit at every slot X__XX___X__XXX___XX_XX__X_______X_XX_____X_XX_X_______X__X_XX_____________X___X___X______X_X__XX____X____X___XX_X_XX___XX______X________X__X______X_________________X___X____X__________XX__X________XX__X_______X_XX_X__XX_X_X_XXX__________X____X____________X__X______XX__XXXXXX_X_____X______X___XXX__X_XX__XX_X__X____X___XXX__X_X__XX____XX____X___XX_______X______X__X_XX_____XX_X__XX_XXX__XXX_____XX___XXXXX___X_XXX_____X_X_____X__X__XX_________XXX_______X___XX___XX_X____XX__XX___X___XX_____X_______X__________X_________X_____________XX___XX__X_X_X___X_XXX_______XXXX_X_XX__X_X___X______XX_______XXX______X_X_X____X____X_X___X_XXX_XXX_X__X___XX___X____X_____X_X_X__X_____________X_X______X_XX_____XXX_____XXX___X________X____X_X___X_____X_X_X___XXXX________X____X__X__X__X___________X______XXX____X__X______X___XX_XX__________XXX_____X__X______XX_XX___X____XXXX______X___X______X____X__X___X__X______X_XX__X____X__XX_XX_____X____XX______X___X_X___X_X_____X__X__XX__XX_XX_X__XXX_X_X___X___X___X___X_X__
Below is the java code. Because I have to calculate this stuff in between frames in a video game, I stay away from decimal math. So the whole implementation is done using int's.
public static void main(String[] args) throws InterruptedException {
nonUniformDispatch();
uniformDispatch();
}
static void nonUniformDispatch() throws InterruptedException {
Random rand = new Random();
double it = 1_000;
int goal = 30;
int dispatches = 0;
for (int i = 0; i < it; i++) {
if (goal > rand.nextInt(100)) {
dispatches++;
System.out.print("X");
} else {
System.out.print("_");
}
}
System.out.println("\n\ndispatches = " + dispatches);
}
static void uniformDispatch() throws InterruptedException {
int totalUnits = 3;
Random rand = new Random();
double it = 1_000;
int dispatches = 0;
int totalSlots = 10;
int unitsRemaining = totalUnits;
int slotsRemaining = totalSlots;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < it; i++) {
// System.out.println("slotsRemaining = " + slotsRemaining + ", unitsRemaining = " + unitsRemaining);
if (slotsRemaining <= unitsRemaining) {
dispatches++;
unitsRemaining--;
sb.append("X");
} else if (unitsRemaining > 0) {
int x = (unitsRemaining * 100) / slotsRemaining;
if (x > rand.nextInt(100)) {
dispatches++;
unitsRemaining--;
sb.append("X");
// System.out.println("x = " + x + ", hit");
} else {
sb.append("_");
// System.out.println("x = " + x + ", miss");
}
} else {
sb.append("_");
// System.out.println("miss");
}
slotsRemaining--;
if (slotsRemaining == 0) {
slotsRemaining = totalSlots;
unitsRemaining = totalUnits;
}
}
System.out.println(sb.toString());
System.out.println("\n\ndispatches = " + dispatches);
TimeUnit.SECONDS.sleep(10);
}
You could take longer time intervals. If you take an interval of $6$ seconds you want an average of $3$ units per interval. Now take a random number $1$ to $5$ for the actual number you will dispatch, then pick that many random times in the interval for the exact times you dispatch them.