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.
Therefore, the exponential growth formula we should use is: x(t) = 10,000 * (1 + 0.05)t = 10,000 * 1.05t . Here t is the number of years passed since 2019. In our case, for the year 2030, we should use t = 11, since this is the difference in the number of years between 2030 and the initial year 2019.
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
).
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.
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);
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With