fix qsort in wormhole code. pointers are hard.

This commit is contained in:
Enno Rehling 2014-09-29 20:38:01 +02:00
parent 3e829e2880
commit cbf9bb8985
1 changed files with 123 additions and 122 deletions

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.
*/ */
#include <platform.h> #include <platform.h>
#include <kernel/config.h> #include <kernel/config.h>
@ -40,186 +40,187 @@
static bool good_region(const region * r) static bool good_region(const region * r)
{ {
return (!fval(r, RF_CHAOTIC) && r->age > 30 && rplane(r) == NULL return (!fval(r, RF_CHAOTIC) && r->age > 30 && rplane(r) == NULL
&& r->units != NULL && r->land != NULL); && r->units != NULL && r->land != NULL);
} }
static int cmp_age(const void *v1, const void *v2) static int cmp_age(const void *v1, const void *v2)
{ {
const region *r1 = (const region *)v1; const region **r1 = (const region **)v1;
const region *r2 = (const region *)v2; const region **r2 = (const region **)v2;
if (r1->age < r2->age) if ((*r1)->age < (*r2)->age)
return -1; return -1;
if (r1->age > r2->age) if ((*r1)->age > (*r2)->age)
return 1; return 1;
return 0; return 0;
} }
typedef struct wormhole_data { typedef struct wormhole_data {
building *entry; building *entry;
region *exit; region *exit;
} wormhole_data; } wormhole_data;
static void wormhole_init(struct attrib *a) static void wormhole_init(struct attrib *a)
{ {
a->data.v = calloc(1, sizeof(wormhole_data)); a->data.v = calloc(1, sizeof(wormhole_data));
} }
static void wormhole_done(struct attrib *a) static void wormhole_done(struct attrib *a)
{ {
free(a->data.v); free(a->data.v);
} }
static int wormhole_age(struct attrib *a) static int wormhole_age(struct attrib *a)
{ {
wormhole_data *data = (wormhole_data *) a->data.v; wormhole_data *data = (wormhole_data *)a->data.v;
int maxtransport = data->entry->size; int maxtransport = data->entry->size;
region *r = data->entry->region; region *r = data->entry->region;
unit *u = r->units; unit *u = r->units;
for (; u != NULL && maxtransport != 0; u = u->next) { for (; u != NULL && maxtransport != 0; u = u->next) {
if (u->building == data->entry) { if (u->building == data->entry) {
message *m = NULL; message *m = NULL;
if (u->number > maxtransport || has_limited_skills(u)) { if (u->number > maxtransport || has_limited_skills(u)) {
m = msg_message("wormhole_requirements", "unit region", u, u->region); m = msg_message("wormhole_requirements", "unit region", u, u->region);
} else if (data->exit != NULL) { }
move_unit(u, data->exit, NULL); else if (data->exit != NULL) {
maxtransport -= u->number; move_unit(u, data->exit, NULL);
m = msg_message("wormhole_exit", "unit region", u, data->exit); maxtransport -= u->number;
add_message(&data->exit->msgs, m); m = msg_message("wormhole_exit", "unit region", u, data->exit);
} add_message(&data->exit->msgs, m);
if (m != NULL) { }
add_message(&u->faction->msgs, m); if (m != NULL) {
msg_release(m); add_message(&u->faction->msgs, m);
} msg_release(m);
}
}
} }
}
remove_building(&r->buildings, data->entry); remove_building(&r->buildings, data->entry);
ADDMSG(&r->msgs, msg_message("wormhole_dissolve", "region", r)); ADDMSG(&r->msgs, msg_message("wormhole_dissolve", "region", r));
/* age returns 0 if the attribute needs to be removed, !=0 otherwise */ /* age returns 0 if the attribute needs to be removed, !=0 otherwise */
return AT_AGE_KEEP; return AT_AGE_KEEP;
} }
static void static void
wormhole_write(const struct attrib *a, const void *owner, struct storage *store) wormhole_write(const struct attrib *a, const void *owner, struct storage *store)
{ {
wormhole_data *data = (wormhole_data *) a->data.v; wormhole_data *data = (wormhole_data *)a->data.v;
write_building_reference(data->entry, store); write_building_reference(data->entry, store);
write_region_reference(data->exit, store); write_region_reference(data->exit, store);
} }
/** conversion code, turn 573, 2008-05-23 */ /** conversion code, turn 573, 2008-05-23 */
static int resolve_exit(variant id, void *address) static int resolve_exit(variant id, void *address)
{ {
building *b = findbuilding(id.i); building *b = findbuilding(id.i);
region **rp = address; region **rp = address;
if (b) { if (b) {
*rp = b->region; *rp = b->region;
return 0; return 0;
} }
*rp = NULL; *rp = NULL;
return -1; return -1;
} }
static int wormhole_read(struct attrib *a, void *owner, struct storage *store) static int wormhole_read(struct attrib *a, void *owner, struct storage *store)
{ {
wormhole_data *data = (wormhole_data *) a->data.v; wormhole_data *data = (wormhole_data *)a->data.v;
resolve_fun resolver = (global.data_version < UIDHASH_VERSION) resolve_fun resolver = (global.data_version < UIDHASH_VERSION)
? resolve_exit : resolve_region_id; ? resolve_exit : resolve_region_id;
read_fun reader = (global.data_version < UIDHASH_VERSION) read_fun reader = (global.data_version < UIDHASH_VERSION)
? read_building_reference : read_region_reference; ? read_building_reference : read_region_reference;
int rb = int rb =
read_reference(&data->entry, store, read_building_reference, read_reference(&data->entry, store, read_building_reference,
resolve_building); resolve_building);
int rr = read_reference(&data->exit, store, reader, resolver); int rr = read_reference(&data->exit, store, reader, resolver);
if (rb == 0 && rr == 0) { if (rb == 0 && rr == 0) {
if (!data->exit || !data->entry) { if (!data->exit || !data->entry) {
return AT_READ_FAIL; return AT_READ_FAIL;
}
} }
} return AT_READ_OK;
return AT_READ_OK;
} }
static attrib_type at_wormhole = { static attrib_type at_wormhole = {
"wormhole", "wormhole",
wormhole_init, wormhole_init,
wormhole_done, wormhole_done,
wormhole_age, wormhole_age,
wormhole_write, wormhole_write,
wormhole_read, wormhole_read,
ATF_UNIQUE ATF_UNIQUE
}; };
static void static void
make_wormhole(const building_type * bt_wormhole, region * r1, region * r2) make_wormhole(const building_type * bt_wormhole, region * r1, region * r2)
{ {
building *b1 = new_building(bt_wormhole, r1, default_locale); building *b1 = new_building(bt_wormhole, r1, default_locale);
building *b2 = new_building(bt_wormhole, r2, default_locale); building *b2 = new_building(bt_wormhole, r2, default_locale);
attrib *a1 = a_add(&b1->attribs, a_new(&at_wormhole)); attrib *a1 = a_add(&b1->attribs, a_new(&at_wormhole));
attrib *a2 = a_add(&b2->attribs, a_new(&at_wormhole)); attrib *a2 = a_add(&b2->attribs, a_new(&at_wormhole));
wormhole_data *d1 = (wormhole_data *) a1->data.v; wormhole_data *d1 = (wormhole_data *)a1->data.v;
wormhole_data *d2 = (wormhole_data *) a2->data.v; wormhole_data *d2 = (wormhole_data *)a2->data.v;
d1->entry = b1; d1->entry = b1;
d2->entry = b2; d2->entry = b2;
d1->exit = b2->region; d1->exit = b2->region;
d2->exit = b1->region; d2->exit = b1->region;
b1->size = bt_wormhole->maxsize; b1->size = bt_wormhole->maxsize;
b2->size = bt_wormhole->maxsize; b2->size = bt_wormhole->maxsize;
ADDMSG(&r1->msgs, msg_message("wormhole_appear", "region", r1)); ADDMSG(&r1->msgs, msg_message("wormhole_appear", "region", r1));
ADDMSG(&r2->msgs, msg_message("wormhole_appear", "region", r2)); ADDMSG(&r2->msgs, msg_message("wormhole_appear", "region", r2));
} }
void create_wormholes(void) void create_wormholes(void)
{ {
#define WORMHOLE_CHANCE 10000 #define WORMHOLE_CHANCE 10000
const building_type *bt_wormhole = bt_find("wormhole"); const building_type *bt_wormhole = bt_find("wormhole");
quicklist *ql, *rlist = 0; quicklist *ql, *rlist = 0;
region *r = regions; region *r = regions;
int qi, i = 0, count = 0; int qi, i = 0, count = 0;
region **match; region **match;
if (bt_wormhole == NULL) if (bt_wormhole == NULL)
return; return;
/* /*
* select a list of regions. we'll sort them by age later. * select a list of regions. we'll sort them by age later.
*/ */
while (r != NULL) { while (r != NULL) {
int next = rng_int() % (2 * WORMHOLE_CHANCE); int next = rng_int() % (2 * WORMHOLE_CHANCE);
while (r != NULL && (next != 0 || !good_region(r))) { while (r != NULL && (next != 0 || !good_region(r))) {
if (good_region(r)) { if (good_region(r)) {
--next; --next;
} }
r = r->next; r = r->next;
}
if (r == NULL)
break;
ql_push(&rlist, r);
++count;
r = r->next;
} }
if (r == NULL)
break;
ql_push(&rlist, r);
++count;
r = r->next;
}
if (count < 2) if (count < 2)
return; return;
match = (region **) malloc(sizeof(region *) * count); match = (region **)malloc(sizeof(region *) * count);
for (ql = rlist,qi = 0; i != count; ql_advance(&ql, &qi, 1)) {
match[i++] = (region *)ql_get(ql, qi);
}
qsort(match, count, sizeof(region *), cmp_age);
ql_free(rlist);
count /= 2; for (ql = rlist, qi = 0; i != count; ql_advance(&ql, &qi, 1)) {
for (i = 0; i != count; ++i) { match[i++] = (region *)ql_get(ql, qi);
make_wormhole(bt_wormhole, match[i], match[i + count]); }
} qsort(match, count, sizeof(region *), cmp_age);
free(match); ql_free(rlist);
count /= 2;
for (i = 0; i != count; ++i) {
make_wormhole(bt_wormhole, match[i], match[i + count]);
}
free(match);
} }
void register_wormholes(void) void register_wormholes(void)
{ {
at_register(&at_wormhole); at_register(&at_wormhole);
} }