news: Rewrite code for "The Bottom Line"

This is one of the lamest ways to sort I've seen in my career: find
the maximum, then for each value from the maximum down, search for
that value.  O(max * MAXNOC^2).  Dates back to Empire 2.

The one advantage this contraption has is it "sorts" in place.  But
memory's cheap.  Fill an array with the data to sort, and sort it with
qsort().  To avoid overtaxing the stack in the (unlikely!) worst case
of everybody taking sectors from everybody, allocate it dynamically.

Also flip sectors_taken[] from short to unsigned short.  Aside: in
theory, the count can overflow, but sector deltas exceeding 65535
don't occur in practice, and if news misreported them, we'd live.  Not
worth complicating the code.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
This commit is contained in:
Markus Armbruster 2016-06-27 21:05:10 +02:00
parent d63b8aa5f0
commit 68e595af8a

View file

@ -38,6 +38,12 @@
#include "optlist.h" #include "optlist.h"
static void preport(struct nwsstr *np); static void preport(struct nwsstr *np);
static int sectwon_cmp(const void *p, const void *q);
struct sectwon {
natid ano, vno;
unsigned short num;
};
int int
news(void) news(void)
@ -50,13 +56,10 @@ news(void)
struct nwsstr nws; struct nwsstr nws;
struct nstr_item nstr; struct nstr_item nstr;
int page_has_news[N_MAX_PAGE + 1]; int page_has_news[N_MAX_PAGE + 1];
short sectors_taken[MAXNOC][MAXNOC]; unsigned short sectors_taken[MAXNOC][MAXNOC];
short sectors_delta;
short max_delta = -1;
short abs_delta;
short k;
int sectors_were_taken = 0;
natid i, j; natid i, j;
int k, n, diff;
struct sectwon *sectwon;
char num[128]; char num[128];
char *verb; char *verb;
@ -111,13 +114,10 @@ news(void)
pr("\n\t === %s ===\n", page_headings[page].name); pr("\n\t === %s ===\n", page_headings[page].name);
heading = page; heading = page;
} }
if (page == N_FRONT && if (nws.nws_vrb == N_WON_SECT ||
(nws.nws_vrb == N_WON_SECT ||
nws.nws_vrb == N_AWON_SECT || nws.nws_vrb == N_AWON_SECT ||
nws.nws_vrb == N_PWON_SECT)) { nws.nws_vrb == N_PWON_SECT)
sectors_taken[nws.nws_ano][nws.nws_vno] += nws.nws_ntm; sectors_taken[nws.nws_ano][nws.nws_vno] += nws.nws_ntm;
sectors_were_taken += nws.nws_ntm;
}
preport(&nws); preport(&nws);
} }
} }
@ -127,45 +127,52 @@ news(void)
return RET_OK; return RET_OK;
} }
if (sectors_were_taken) { n = 0;
for (i = 0; i < MAXNOC; ++i) {
for (j = 0; j < i; ++j)
n += !!(sectors_taken[i][j] - sectors_taken[j][i]);
}
sectwon = malloc(sizeof(*sectwon) * n);
n = 0;
for (i = 0; i < MAXNOC; ++i) { for (i = 0; i < MAXNOC; ++i) {
for (j = 0; j < i; ++j) { for (j = 0; j < i; ++j) {
sectors_delta = sectors_taken[i][j] - sectors_taken[j][i]; diff = sectors_taken[i][j] - sectors_taken[j][i];
if (max_delta < abs(sectors_delta)) if (diff > 0) {
max_delta = abs(sectors_delta); sectwon[n].ano = i;
} sectwon[n].vno = j;
} sectwon[n].num = diff;
pr("\n\t === The Bottom Line ==\n"); n++;
for (k = max_delta; k > 0; --k) { } else if (diff < 0) {
for (i = 0; i < MAXNOC; ++i) { sectwon[n].ano = j;
for (j = 0; j < i; ++j) { sectwon[n].vno = i;
sectors_delta = sectors_taken[i][j] - sectwon[n].num = -diff;
sectors_taken[j][i]; n++;
abs_delta = abs(sectors_delta);
if (abs_delta != k)
continue;
if (abs_delta == 1)
verb = "stole";
else if (abs_delta < 4)
verb = "took";
else if (abs_delta < 8)
verb = "captured";
else
verb = "seized";
if (sectors_delta > 0) {
numstr(num, abs_delta);
pr("%s %s %s sector%s from %s\n", cname(i), verb,
num, splur(sectors_delta), cname(j));
} else if (sectors_delta < 0) {
numstr(num, abs_delta);
pr("%s %s %s sector%s from %s\n", cname(j), verb,
num, splur(-sectors_delta), cname(i));
}
}
} }
} }
} }
qsort(sectwon, n, sizeof(*sectwon), sectwon_cmp);
if (n) {
pr("\n\t === The Bottom Line ==\n");
for (k = 0; k < n; k++) {
if (sectwon[k].num == 1)
verb = "stole";
else if (sectwon[k].num < 4)
verb = "took";
else if (sectwon[k].num < 8)
verb = "captured";
else
verb = "seized";
numstr(num, sectwon[k].num);
pr("%s %s %s sector%s from %s\n",
cname(sectwon[k].ano), verb, num, splur(sectwon[k].num),
cname(sectwon[k].vno));
}
}
free(sectwon);
return RET_OK; return RET_OK;
} }
@ -212,3 +219,18 @@ preport(struct nwsstr *np)
np->nws_ntm = 0; np->nws_ntm = 0;
return; return;
} }
static int
sectwon_cmp(const void *p, const void *q)
{
const struct sectwon *a = p, *b = q;
int cmp;
cmp = b->num - a->num;
if (cmp)
return cmp;
cmp = b->ano - a->ano;
if (cmp)
return cmp;
return b->vno - a->vno;
}