Как смоделировать экспоненциальный рост

Я работаю над игрой, и в ней я хочу, чтобы рост происходил в геометрической прогрессии - так, например, получение от 2 до 3 человек может занять примерно то же время, что и увеличение от 2 до 3 миллионов человек. Однако я бы хотел, чтобы этот рост был случайным, если это возможно, чтобы сделать его более реалистичным. Пока у меня есть метод, который хорошо работает:

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);
        }

Однако я понимаю, что это не будет устойчивым. Он работает примерно 60 раз в секунду (с такой величиной), и как только он достигает уровня в миллионы, он может в конечном итоге выполнять миллиарды операций в секунду - многовато для такой простой проверки. Я поставлю его на интервал, если нужно, но я бы предпочел оставить его случайным.

Я попытался найти уравнение для вероятности, но в итоге получил:

Σ (99 ^ r / 1000 ^ (r + 1)) от r = 0 до p (где p = вероятность)

Есть ли простой способ изменить эту вероятность на тест или более простой метод в Java для достижения такой цели.

Если это поможет, я использую LibGdx в качестве движка.

Вместо того, чтобы повторять цикл N раз для вашей популяции и увеличивать его на единицу, почему бы не выбрать число от 1 до 1000 и умножить на N?

Michael 11.04.2018 17:28

Вы имеете в виду, выберите число, например, 42, и умножьте его на численность населения - например. 3. Это дало бы 126 - слишком большое увеличение, или вы имеете в виду, что есть 1 шанс из 1000 увеличиться на 3 - и в этом случае он упустит популяцию 4 и 5

Joseph Keane 11.04.2018 17:37

Если условия строительства и питания соблюдены, шанс разделения (популяция ++) для каждого человека составляет 1/1000. Таким образом, для N человек в среднем будет n / 1000 разделений за тик. Почему бы просто не добавить (n + - случайным образом) / 1000 человек за тик? Случайным образом должно быть нормальное распределение, основанное на n. Даже с 20 людьми вы редко получите случайное = 1500, за +2 популярности за тик, но обычно это будет +0 или +1. Может потребоваться небольшая настройка на начальном этапе игры, когда pop невелик (чтобы не всегда округляться до нуля), но после этого все должно работать нормально.

the_pwner224 11.04.2018 17:52

@leoderprofi Хороший момент, BigInteger может быть решением, но неизменным.

Master Yoda 11.04.2018 18:02
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
6
4
1 116
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Здесь

с вашим примером 2-3 от 2М до 3М я бы сказал, используйте оператор * 1.5

пример: каждые 60 лет -> человек = человек * 1,5

груша, я не совсем понимаю, что тебе нужно

lio

Но я хочу, чтобы он увеличивался медленно и с приращением, чтобы вы могли видеть, что числа увеличиваются быстрее, но, может быть, до 1000 вы все равно будете видеть увеличение численности населения. В этом методе это будет: 2 -> 3 -> 4 -> 6 -> 9 -> 13 и т. д. И в любом случае это слишком быстро - проверка происходит каждые 1/60 секунды, а не каждые 60 секунд.

Joseph Keane 11.04.2018 17:42
Ответ принят как подходящий

Кажется, что, если предположить, что случайные числа распределены равномерно, вы увеличите численность населения в среднем на n / 1000 для численности населения n.

Чтобы подражать этому, было бы неплохо просто разделить populationCount на 500 и использовать ThreadLocalRandom#nextGaussian, чтобы определить, на сколько увеличить populationCount, что позволит вам избавиться от цикла for:

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.
    }
}

Для популяции 10,000 это увеличило бы популяцию в среднем на 10 (в данном случае колеблется от 0 до 20, но в пользу среднего значения 10 из-за использования nextGaussian).

Превратите меня в использование гауссовских распределений. Я думаю, что это лучший ответ, поскольку он поддерживает случайность, которую хочет OP, а не постоянный рост.

xtratic 11.04.2018 18:08

Явная формула экспоненциального роста: х_t = х_0 * (1 + г) ^ т где t - ваш интервал (в вашем случае 60 интервалов в секунду) а r - ваш темп роста. Итак, формула увеличения одного интервала:

х_1 = х_0 * (1 + г)

где x_0 - предыдущая популяция.

Итак, в основном, вместо того, чтобы перебирать весь ваш подсчет населения на каждом интервале, вы можете просто это (со скоростью роста 0,1%):

Data.main.setPopulationCount(populationCount + Math.floor(populationCount * 0.001f));

Для уменьшения численности населения просто вычтите, а не прибавляйте.

Data.main.setPopulationCount(populationCount - Math.floor(populationCount * 0.001f));

Чтобы интегрировать случайность, вы можете сделать что-то вроде этого:

Data.main.setPopulationCount(populationCount + Math.floor(populationCount * 0.001f * random.nextFloat()));

Таким образом, ваш темп роста будет колебаться от 0% до 100% на каждом приращении.

Тогда останется только поэкспериментировать со скоростью роста.

Эту стратегию следует использовать только тогда, когда популяция превысит примерно 5 * (1 / темп роста), иначе Math.floor сделает его слишком неточным или даже уменьшит любой рост.

В настоящее время вы делаете следующее: у каждого человека есть шанс 1 из 1000 произвести нового человека. Ваш код сходит с ума от больших чисел, потому что вы проверяете всех.

Для больших чисел ваш алгоритм эквивалентен умножению вашего населения на 1,001 (1 + 1/1000). Случайный аспект исчезнет для больших чисел (как объясняет здесь)

Но для небольшого числа действительно важен случайный выбор. Я думаю, что лучший способ справиться с этим - определить уровень популяции, на котором вы используете умножение и на котором вы используете свой метод.

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);
            }
        }
    }
}

Другие вопросы по теме