Reputation: 321
I'm working on a game, and in it I want growth to happen exponentially - so, for example, getting from 2 to 3 people might take around the same time as getting from 2 million to 3 million people. However, I would like this growth to be random if possible to make it more realistic. So far I have a method that works well:
if (buildingCount > populationCount && foodCount > populationCount)
for(int i=1;i<populationCount;i++) {
int randomInt = random.nextInt(1000);
if (randomInt == 42) {
Data.main.setPopulationCount(populationCount+1);
}
}
if ((buildingCount < populationCount || foodCount < populationCount)&&populationCount>2)
for(int i=1;i<populationCount;i++) {
int randomInt = random.nextInt(1000);
if (randomInt == 888) {
Data.main.setPopulationCount(populationCount-1);
}
However, I realise this will not be sustainable. It runs approximately 60 times a second (on that magnitude), and once it reaches levels of millions, it may end up running billions of operations per second - a bit much for such a simple check. I'll put it on an interval if I have to, but I'd rather keep it random.
I tried to find an equation for the probability but ended up with:
Σ(99^r/1000^(r+1)) from r=0 to p (where p = probability)
Is there any easy way to change that probability to a test, or a simpler method in Java to accomplish such a purpose.
If it helps I'm using LibGdx as an engine.
Upvotes: 6
Views: 2236
Reputation: 241
The explicit formula for exponential growth is: x_t=x_0*(1+r)^t where t is your interval (in your case there are 60 intervals per second) and r is your growth rate. So the formula for the increase in one interval is:
x_1=x_0*(1+r)
with x_0 being the previous population.
So basically, instead of looping over your whole population count on every interval, you can just this (with a growth rate of 0.1%):
Data.main.setPopulationCount(populationCount + Math.floor(populationCount * 0.001f));
For population decrease just subtract instead of adding.
Data.main.setPopulationCount(populationCount - Math.floor(populationCount * 0.001f));
In order to integrate randomness you could do something like this:
Data.main.setPopulationCount(populationCount + Math.floor(populationCount * 0.001f * random.nextFloat()));
That way your growth rate would fluctuate between 0% and 100% on each increment.
Then it would only be a matter of experimenting with the growth rate.
This strategy should only be employed though as soon as the population exceeds about 5 * (1 / growth rate), for otherwise Math.floor will render it too inaccurate or even diminish any growth.
Upvotes: 1
Reputation: 29730
It seems that, assuming the distribution of random numbers is uniform, you'll increase the population count by n / 1000
, on average, for a population count of n
.
To emulate this, it might be a good idea to just divide populationCount
by 500
and use ThreadLocalRandom#nextGaussian
to determine how much to increment populationCount
by, allowing you to rid yourself of the for-loop:
if (buildingCount > populationCount && foodCount > populationCount) {
if (populationCount > 1000) {
int randomNum = (int) ((ThreadLocalRandom.current().nextGaussian() / 2 + 0.5) * populationCount / 500);
Data.main.setPopulationCount(populationCount + randomNum);
} else {
// Original for-loop here for populations less than 1000.
}
}
For a population of 10,000
, this would increase the population by an average of 10
(ranges from 0
to 20
in this case, but favors a mean of 10
due to the use of nextGaussian
).
Upvotes: 4
Reputation: 2208
Currently what you are doing is : for every person it has a chance of 1 over 1000 to produce a new person. Your code is going crazy on big numbers cause you check everyone.
For big numbers your algorithm is equivalent as multiplying your population by 1.001 (1+1/1000). The random aspect will disappear for big numbers (as explain here)
But for small number the random is really important. I think the best way to handle this is to define a population level over which you use a multiplication and under which you use your method.
if (buildingCount > populationCount && foodCount > populationCount)
if(populationCount > 10000) { //I use 10000 has population level but do what you want
for(int i=1;i<populationCount;i++) {
int randomInt = random.nextInt(1000);
if (randomInt == 42) {
Data.main.setPopulationCount(populationCount+1);
}
}
}
}
Upvotes: 1
Reputation: 51
Here
with your exemple 2-3 2M to 3M i would say use a *1.5 operator
exemple: every 60S --> people=people*1.5
pearps i'am don't understand clearly your need
lio
Upvotes: -1