From a569ef67e877b5871d04a4b670402063171d803b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 15 Sep 2017 21:52:20 +0200 Subject: [PATCH] sortiere unit.skills nach id. TODO: binary search statt linear, read_unit optimization https://trello.com/c/ydUTDGgl/616-sort-unitskills-binary-search --- src/kernel/unit.c | 47 +++++++++++++++++++---------------- src/kernel/unit.test.c | 56 ++++++++++++++++++++++++++++++++++++------ src/reports.test.c | 10 ++++---- 3 files changed, 80 insertions(+), 33 deletions(-) diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 44e9445b7..b2eeec055 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -773,7 +773,7 @@ int get_level(const unit * u, skill_t id) assert(id != NOSKILL); if (skill_enabled(id)) { skill *sv = u->skills; - while (sv != u->skills + u->skill_size) { + while (sv != u->skills + u->skill_size && sv->id <= id) { if (sv->id == id) { return sv->level; } @@ -795,7 +795,7 @@ void set_level(unit * u, skill_t sk, int value) remove_skill(u, sk); return; } - while (sv != u->skills + u->skill_size) { + while (sv != u->skills + u->skill_size && sv->id <= sk) { if (sv->id == sk) { sk_set(sv, value); return; @@ -1186,35 +1186,39 @@ void set_number(unit * u, int count) void remove_skill(unit * u, skill_t sk) { - skill *sv = u->skills; - for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + int i; + skill *sv; + for (i = 0; i != u->skill_size; ++i) { + sv = u->skills + i; if (sv->id == sk) { - skill *sl = u->skills + u->skill_size - 1; - if (sl != sv) { - *sv = *sl; - } + memmove(sv, sv + 1, (u->skill_size - 1) * sizeof(skill)); --u->skill_size; return; } } } -skill *add_skill(unit * u, skill_t id) +skill *add_skill(unit * u, skill_t sk) { - skill *sv = u->skills; -#ifndef NDEBUG - for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - assert(sv->id != id); + skill *sv; + int i; + + for (i=0; i != u->skill_size; ++i) { + sv = u->skills+i; + if (sv->id >= sk) break; + } + u->skills = realloc(u->skills, (1 + u->skill_size) * sizeof(skill)); + sv = u->skills + i; + if (i < u->skill_size) { + assert(sv->id != sk); + memmove(sv + 1, sv, sizeof(skill) * (u->skill_size - i)); } -#endif ++u->skill_size; - u->skills = realloc(u->skills, u->skill_size * sizeof(skill)); - sv = (u->skills + u->skill_size - 1); sv->level = 0; sv->weeks = 1; sv->old = 0; - sv->id = id; - if (id == SK_MAGIC && u->faction && !fval(u->faction, FFL_NPC)) { + sv->id = sk; + if (sk == SK_MAGIC && u->faction && !fval(u->faction, FFL_NPC)) { assert(u->number <= 1); assert(max_magicians(u->faction) >= u->number); } @@ -1224,9 +1228,10 @@ skill *add_skill(unit * u, skill_t id) skill *unit_skill(const unit * u, skill_t sk) { skill *sv = u->skills; - while (sv != u->skills + u->skill_size) { - if (sv->id == sk) + while (sv != u->skills + u->skill_size && sv->id <= sk) { + if (sv->id == sk) { return sv; + } ++sv; } return NULL; @@ -1235,7 +1240,7 @@ skill *unit_skill(const unit * u, skill_t sk) bool has_skill(const unit * u, skill_t sk) { skill *sv = u->skills; - while (sv != u->skills + u->skill_size) { + while (sv != u->skills + u->skill_size && sv->id <= sk) { if (sv->id == sk) { return (sv->level > 0); } diff --git a/src/kernel/unit.test.c b/src/kernel/unit.test.c index 2abb8c85c..2e4ce3568 100644 --- a/src/kernel/unit.test.c +++ b/src/kernel/unit.test.c @@ -31,7 +31,7 @@ static void test_remove_empty_units(CuTest *tc) { unit *u; int uid; - test_cleanup(); + test_setup(); test_create_world(); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); @@ -48,7 +48,7 @@ static void test_remove_empty_units_in_region(CuTest *tc) { unit *u; int uid; - test_cleanup(); + test_setup(); test_create_world(); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); @@ -69,7 +69,7 @@ static void test_remove_units_without_faction(CuTest *tc) { unit *u; int uid; - test_cleanup(); + test_setup(); test_create_world(); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); @@ -85,7 +85,7 @@ static void test_remove_units_with_dead_faction(CuTest *tc) { unit *u; int uid; - test_cleanup(); + test_setup(); test_create_world(); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); @@ -101,7 +101,7 @@ static void test_scale_number(CuTest *tc) { unit *u; const struct potion_type *ptype; - test_cleanup(); + test_setup(); test_create_world(); ptype = new_potiontype(it_get_or_create(rt_get_or_create("hodor")), 1); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); @@ -122,7 +122,7 @@ static void test_scale_number(CuTest *tc) { static void test_unit_name(CuTest *tc) { unit *u; - test_cleanup(); + test_setup(); test_create_world(); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); renumber_unit(u, 666); @@ -334,9 +334,50 @@ static void test_inside_building(CuTest *tc) { test_cleanup(); } +static void test_skills(CuTest *tc) { + unit *u; + skill *sv; + test_setup(); + u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + sv = add_skill(u, SK_ALCHEMY); + CuAssertPtrNotNull(tc, sv); + CuAssertPtrEquals(tc, sv, u->skills); + CuAssertIntEquals(tc, 1, u->skill_size); + CuAssertIntEquals(tc, SK_ALCHEMY, sv->id); + CuAssertIntEquals(tc, 0, sv->level); + CuAssertIntEquals(tc, 1, sv->weeks); + CuAssertIntEquals(tc, 0, sv->old); + sv = add_skill(u, SK_BUILDING); + CuAssertPtrNotNull(tc, sv); + CuAssertIntEquals(tc, 2, u->skill_size); + CuAssertIntEquals(tc, SK_ALCHEMY, u->skills[0].id); + CuAssertIntEquals(tc, SK_BUILDING, u->skills[1].id); + sv = add_skill(u, SK_LONGBOW); + CuAssertPtrNotNull(tc, sv); + CuAssertPtrEquals(tc, sv, unit_skill(u, SK_LONGBOW)); + CuAssertIntEquals(tc, 3, u->skill_size); + CuAssertIntEquals(tc, SK_ALCHEMY, u->skills[0].id); + CuAssertIntEquals(tc, SK_LONGBOW, u->skills[1].id); + CuAssertIntEquals(tc, SK_BUILDING, u->skills[2].id); + CuAssertTrue(tc, !has_skill(u, SK_LONGBOW)); + set_level(u, SK_LONGBOW, 1); + CuAssertTrue(tc, has_skill(u, SK_LONGBOW)); + remove_skill(u, SK_LONGBOW); + CuAssertIntEquals(tc, SK_BUILDING, u->skills[1].id); + CuAssertIntEquals(tc, 2, u->skill_size); + remove_skill(u, SK_LONGBOW); + CuAssertIntEquals(tc, SK_BUILDING, u->skills[1].id); + CuAssertIntEquals(tc, 2, u->skill_size); + remove_skill(u, SK_BUILDING); + CuAssertIntEquals(tc, SK_ALCHEMY, u->skills[0].id); + CuAssertIntEquals(tc, 1, u->skill_size); + CuAssertTrue(tc, !has_skill(u, SK_LONGBOW)); + test_cleanup(); +} + static void test_limited_skills(CuTest *tc) { unit *u; - test_cleanup(); + test_setup(); u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); CuAssertIntEquals(tc, false, has_limited_skills(u)); set_level(u, SK_ENTERTAINMENT, 1); @@ -592,6 +633,7 @@ CuSuite *get_unit_suite(void) SUITE_ADD_TEST(suite, test_skill_familiar); SUITE_ADD_TEST(suite, test_age_familiar); SUITE_ADD_TEST(suite, test_inside_building); + SUITE_ADD_TEST(suite, test_skills); SUITE_ADD_TEST(suite, test_limited_skills); SUITE_ADD_TEST(suite, test_renumber_unit); SUITE_ADD_TEST(suite, test_name_unit); diff --git a/src/reports.test.c b/src/reports.test.c index 58ac425f1..7c6e8ccf4 100644 --- a/src/reports.test.c +++ b/src/reports.test.c @@ -279,13 +279,13 @@ static void test_bufunit(CuTest *tc) { bufunit(u->faction, u, 0, 0, buffer, sizeof(buffer)); CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv.", buffer); - set_level(u, SK_SAILING, 1); - bufunit(u->faction, u, 0, 0, buffer, sizeof(buffer)); - CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Segeln 1.", buffer); - set_level(u, SK_ALCHEMY, 1); bufunit(u->faction, u, 0, 0, buffer, sizeof(buffer)); - CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Segeln 1, Alchemie 2.", buffer); + CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Alchemie 2.", buffer); + + set_level(u, SK_SAILING, 1); + bufunit(u->faction, u, 0, 0, buffer, sizeof(buffer)); + CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Alchemie 2, Segeln 1.", buffer); f = test_create_faction(0); f->locale = get_or_create_locale("de");