Merge branch 'stm2-peasantgrowth_acceleration'

This commit is contained in:
Enno Rehling 2015-01-30 22:11:33 +01:00
commit 02f92f7932
9 changed files with 127 additions and 34 deletions

View File

@ -3658,6 +3658,13 @@
<text locale="fr">"$unit($unit): '$order($command)' - The unit already uses $resource($using,0)."</text> <text locale="fr">"$unit($unit): '$order($command)' - The unit already uses $resource($using,0)."</text>
<text locale="en">"$unit($unit): '$order($command)' - The unit already uses $resource($using,0)."</text> <text locale="en">"$unit($unit): '$order($command)' - The unit already uses $resource($using,0)."</text>
</message> </message>
<message name="peasantluck_success" section="events">
<type>
<arg name="births" type="int"/>
</type>
<text locale="de">"$if($eq($births,1),"Einen Bauern","$int($births) Bauern") besucht unverhofft der Storch."</text>
<text locale="en">"The stork paid an unexpected visit to $if($eq($births,1),"a peasant","$int($births) peasants")."</text>
</message>
<message name="shipsink" section="events"> <message name="shipsink" section="events">
<type> <type>
<arg name="ship" type="ship"/> <arg name="ship" type="ship"/>

View File

@ -258,7 +258,58 @@ static void calculate_emigration(region * r)
} }
} }
/** Bauern vermehren sich */
static float peasant_growth_factor(void)
{
return get_param_flt(global.parameters, "rules.peasants.growth.factor", 0.0001F * PEASANTGROWTH);
}
#ifdef SLOWLUCK
int peasant_luck_effect(int peasants, int luck, int maxp, float variance) {
int n, births=0;
float factor = peasant_growth_factor();
for (n = peasants; n && luck; --n) {
int chances = 0;
if (luck > 0) {
--luck;
chances += PEASANTLUCK;
}
while (chances--) {
if (rng_double() < factor) {
/* Only raise with 75% chance if peasants have
* reached 90% of maxpopulation */
if (peasants / (float)maxp < 0.9 || chance(PEASANTFORCE)) {
++births;
}
}
}
}
return births;
}
#else
static float peasant_luck_factor(void)
{
return get_param_flt(global.parameters, "rules.peasants.peasantluck.factor", PEASANTLUCK);
}
int peasant_luck_effect(int peasants, int luck, int maxp, float variance)
{
int births = 0;
double mean = _min(luck, peasants) * peasant_luck_factor()
* peasant_growth_factor() * ((peasants / (float)maxp < .9) ? 1 :
PEASANTFORCE);
births = RAND_ROUND(normalvariate(mean, variance * mean));
if (births <= 0)
births = 1;
if (births > peasants / 2)
births = peasants / 2 + 1;
return births;
}
#endif
static void peasants(region * r) static void peasants(region * r)
{ {
@ -268,42 +319,20 @@ static void peasants(region * r)
int n, satiated; int n, satiated;
int dead = 0; int dead = 0;
/* Bis zu 1000 Bauern können Zwillinge bekommen oder 1000 Bauern
* wollen nicht! */
if (peasants > 0 && get_param_int(global.parameters, "rules.peasants.growth", 1)) { if (peasants > 0 && get_param_int(global.parameters, "rules.peasants.growth", 1)) {
int glueck = 0; int luck = 0;
double fraction = peasants * 0.0001F * PEASANTGROWTH; double fraction = peasants * peasant_growth_factor();
int births = (int)fraction; int births = RAND_ROUND(fraction);
attrib *a = a_find(r->attribs, &at_peasantluck); attrib *a = a_find(r->attribs, &at_peasantluck);
if (rng_double() < (fraction - births)) {
/* because we don't want regions that never grow pga. rounding. */
++births;
}
if (a != NULL) { if (a != NULL) {
glueck = a->data.i * 1000; luck = a->data.i * 1000;
} }
for (n = peasants; n; --n) { luck = peasant_luck_effect(peasants, luck, maxp, .5);
int chances = 0; ADDMSG(&r->msgs, msg_message("peasantluck_success", "births", luck));
if (glueck > 0) { peasants += births + luck;
--glueck;
chances += PEASANTLUCK;
}
while (chances--) {
if (rng_int() % 10000 < PEASANTGROWTH) {
/* Only raise with 75% chance if peasants have
* reached 90% of maxpopulation */
if (peasants / (float)maxp < 0.9 || chance(PEASANTFORCE)) {
++births;
}
}
}
}
peasants += births;
} }
/* Alle werden satt, oder halt soviele für die es auch Geld gibt */ /* Alle werden satt, oder halt soviele für die es auch Geld gibt */

View File

@ -106,7 +106,7 @@ extern "C" {
const struct unit *u, int modifier); const struct unit *u, int modifier);
int armedmen(const struct unit *u, bool siege_weapons); int armedmen(const struct unit *u, bool siege_weapons);
void force_leave(struct region *r); void force_leave(struct region *r);
int peasant_luck_effect(int peasants, int luck, int maxp, float variance);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -16,6 +16,7 @@
#include <util/base36.h> #include <util/base36.h>
#include <util/language.h> #include <util/language.h>
#include <util/message.h> #include <util/message.h>
#include <util/rand.h>
#include <CuTest.h> #include <CuTest.h>
#include <tests.h> #include <tests.h>
@ -691,6 +692,32 @@ static void test_reserve_self(CuTest *tc) {
test_cleanup(); test_cleanup();
} }
static void statistic_test(CuTest *tc, int peasants, int luck, int maxp,
float variance, int min_value, int max_value)
{
int effect, i;
for (i = 0; i < 1000; ++i) {
effect = peasant_luck_effect(peasants, luck, maxp, variance);
CuAssertTrue(tc, min_value <= effect);
CuAssertTrue(tc, max_value >= effect);
}
}
static void test_peasant_luck_effect(CuTest *tc)
{
set_param(&global.parameters, "rules.peasants.peasantluck.factor", "10");
set_param(&global.parameters, "rules.peasants.growth.factor", "0.001");
statistic_test(tc, 100, 2, 1000, 0, 1, 1);
statistic_test(tc, 1000, 400, 1000, 0, (int)(400 * 10 * 0.001 * .75),
(int)(400 * 10 * 0.001 * .75));
statistic_test(tc, 1000, 1000, 2000, .5f, 1, 501);
set_param(&global.parameters, "rules.peasants.growth.factor", "1");
statistic_test(tc, 1000, 1000, 1000, 0, 501, 501);
}
CuSuite *get_laws_suite(void) CuSuite *get_laws_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
@ -721,6 +748,7 @@ CuSuite *get_laws_suite(void)
SUITE_ADD_TEST(suite, test_force_leave_buildings); SUITE_ADD_TEST(suite, test_force_leave_buildings);
SUITE_ADD_TEST(suite, test_force_leave_ships); SUITE_ADD_TEST(suite, test_force_leave_ships);
SUITE_ADD_TEST(suite, test_force_leave_ships_on_ocean); SUITE_ADD_TEST(suite, test_force_leave_ships_on_ocean);
SUITE_ADD_TEST(suite, test_peasant_luck_effect);
return suite; return suite;
} }

View File

@ -8,7 +8,7 @@
This program may not be used, modified or distributed This program may not be used, modified or distributed
without prior permission by the authors of Eressea. without prior permission by the authors of Eressea.
*/ */
/* /*
* Contains defines for the "free" game (Eressea) . * Contains defines for the "free" game (Eressea) .
@ -25,9 +25,9 @@
/* Vermehrungsrate Bauern in 1/10000. /* Vermehrungsrate Bauern in 1/10000.
* TODO: Evt. Berechnungsfehler, reale Vermehrungsraten scheinen höher. */ * TODO: Evt. Berechnungsfehler, reale Vermehrungsraten scheinen höher. */
#define PEASANTGROWTH 10 #define PEASANTGROWTH 10
#define BATTLE_KILLS_PEASANTS 20 #define BATTLE_KILLS_PEASANTS 20
#define PEASANTLUCK 10 #define PEASANTLUCK 10
#define ROW_FACTOR 3 /* factor for combat row advancement rule */ #define ROW_FACTOR 3 /* factor for combat row advancement rule */

View File

@ -53,6 +53,7 @@ int RunAllTests(void)
RUN_TESTS(suite, umlaut); RUN_TESTS(suite, umlaut);
RUN_TESTS(suite, unicode); RUN_TESTS(suite, unicode);
RUN_TESTS(suite, strings); RUN_TESTS(suite, strings);
RUN_TESTS(suite, rng);
/* kernel */ /* kernel */
RUN_TESTS(suite, alliance); RUN_TESTS(suite, alliance);
RUN_TESTS(suite, unit); RUN_TESTS(suite, unit);

View File

@ -9,6 +9,7 @@ bsdstring.test.c
functions.test.c functions.test.c
umlaut.test.c umlaut.test.c
unicode.test.c unicode.test.c
rng.test.c
) )
SET(_FILES SET(_FILES

View File

@ -39,6 +39,7 @@ extern "C" {
# define rng_double ((rand()%RAND_MAX)/(double)RAND_MAX) # define rng_double ((rand()%RAND_MAX)/(double)RAND_MAX)
# define RNG_RAND_MAX RAND_MAX # define RNG_RAND_MAX RAND_MAX
#endif #endif
#define RAND_ROUND(fractional) ((rng_double() < fractional-(int)fractional)?((int)fractional+1):((int)fractional))
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

26
src/util/rng.test.c Normal file
View File

@ -0,0 +1,26 @@
#include <CuTest.h>
#include <ctype.h>
#include "rng.h"
static void test_rng_round(CuTest * tc)
{
double f;
int i, r;
for (i = 0; i < 1000; ++i) {
f = rng_double();
r = RAND_ROUND(f);
CuAssertTrue(tc, f >= 0);
CuAssertTrue(tc, r <= (int ) f + 1);
CuAssertTrue(tc, r >= (int ) f);
CuAssertTrue(tc, r == (int ) r);
CuAssertTrue(tc, r == RAND_ROUND(r));
}
}
CuSuite *get_rng_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_rng_round);
return suite;
}