day 5, pretty blinkenlights mem, awful performance
This commit is contained in:
230
day5.c
Normal file
230
day5.c
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
#include "lib.h"
|
||||||
|
|
||||||
|
#define DBG 0
|
||||||
|
#define PRETTY 1
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned char input[] = {
|
||||||
|
#embed "day5_input.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned char test[] = {
|
||||||
|
#embed "day5_test.txt"
|
||||||
|
};
|
||||||
|
|
||||||
|
#if PRETTY
|
||||||
|
struct line {
|
||||||
|
union {
|
||||||
|
unsigned char l[64];
|
||||||
|
struct {
|
||||||
|
unsigned char s[16];
|
||||||
|
unsigned char pad0[4];
|
||||||
|
unsigned char e[16];
|
||||||
|
unsigned char pad1[4];
|
||||||
|
num sv;
|
||||||
|
num ev;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(struct line) == 0x40);
|
||||||
|
#else
|
||||||
|
struct line {
|
||||||
|
num sv;
|
||||||
|
num ev;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
alignas(0x40) static
|
||||||
|
struct line ranges[256];
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned long do_part1(size_t file_len, unsigned char file[file_len]) {
|
||||||
|
unsigned char *s = file;
|
||||||
|
unsigned long result = 0;
|
||||||
|
|
||||||
|
memset(ranges, 0, sizeof(ranges));
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct line *d = ranges;
|
||||||
|
do {
|
||||||
|
unsigned char *tmp;
|
||||||
|
d->sv = grabbcd(s, &tmp);
|
||||||
|
#if PRETTY
|
||||||
|
memcpy(d->s, s, tmp - s);
|
||||||
|
#endif
|
||||||
|
s = tmp;
|
||||||
|
s++;
|
||||||
|
d->ev = grabbcd(s, &tmp);
|
||||||
|
#if PRETTY
|
||||||
|
memcpy(d->e, s, tmp - s);
|
||||||
|
#endif
|
||||||
|
s = tmp;
|
||||||
|
s++;
|
||||||
|
d++;
|
||||||
|
} while (*s != '\n');
|
||||||
|
d->sv = 0;
|
||||||
|
#if PRETTY
|
||||||
|
d->pad0[0] = 'F';
|
||||||
|
d->pad0[1] = 'I';
|
||||||
|
d->pad0[2] = 'N';
|
||||||
|
d->pad0[3] = 'I';
|
||||||
|
#endif
|
||||||
|
s++;
|
||||||
|
|
||||||
|
do {
|
||||||
|
bcdint id = grabbcd(s, &s);
|
||||||
|
for (d = ranges; d->sv; d++) {
|
||||||
|
bcdint ds = d->sv;
|
||||||
|
bcdint de = d->ev;
|
||||||
|
if (id >= ds && id <= de) {
|
||||||
|
result++;
|
||||||
|
goto next_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next_id:
|
||||||
|
s++;
|
||||||
|
} while (s != &file[file_len]);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned long do_part2(size_t file_len, unsigned char file[file_len]) {
|
||||||
|
unsigned char *s = file;
|
||||||
|
unsigned long result = 0;
|
||||||
|
|
||||||
|
memset(ranges, 0, sizeof(ranges));
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct line *d = ranges;
|
||||||
|
do {
|
||||||
|
unsigned char *tmp;
|
||||||
|
d->sv = grabbcd(s, &tmp);
|
||||||
|
#if PRETTY
|
||||||
|
snprintd(d->sv, sizeof(d->s), d->s);
|
||||||
|
#endif
|
||||||
|
s = tmp;
|
||||||
|
s++;
|
||||||
|
d->ev = grabbcd(s, &tmp);
|
||||||
|
#if PRETTY
|
||||||
|
snprintd(d->ev, sizeof(d->e), d->e);
|
||||||
|
#endif
|
||||||
|
s = tmp;
|
||||||
|
s++;
|
||||||
|
d++;
|
||||||
|
} while (*s != '\n');
|
||||||
|
d->sv = 0;
|
||||||
|
#if PRETTY
|
||||||
|
d->pad0[0] = 'F';
|
||||||
|
d->pad0[1] = 'I';
|
||||||
|
d->pad0[2] = 'N';
|
||||||
|
d->pad0[3] = 'I';
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (struct line *di = ranges; di->sv; di++) {
|
||||||
|
bcdint dis = di->sv;
|
||||||
|
bcdint die = di->ev;
|
||||||
|
if (dis == -1) continue;
|
||||||
|
for (struct line *dj = ranges; dj->sv; dj++) {
|
||||||
|
if (dj == di) continue;
|
||||||
|
bcdint djs = dj->sv;
|
||||||
|
bcdint dje = dj->ev;
|
||||||
|
if (djs == -1) continue;
|
||||||
|
if (djs <= die && djs >= dis) {
|
||||||
|
djs = bcdadd(die, 1);
|
||||||
|
}
|
||||||
|
if (dje >= dis && dje <= die) {
|
||||||
|
dje = bcdsub(dis, 1);
|
||||||
|
}
|
||||||
|
if (djs == dj->sv && dje == dj->ev)
|
||||||
|
continue;
|
||||||
|
if (dje < djs) {
|
||||||
|
#if DBG
|
||||||
|
print("FOR: "); printd(dis); print(" "); printd(die); print("\n");
|
||||||
|
print(" "); printd(dj->sv); print(" "); printd(dj->ev); print("\n");
|
||||||
|
print(" -> "); printd(djs); print(" "); printd(dje); print(" BAD\n");
|
||||||
|
#endif
|
||||||
|
dj->sv = -1;
|
||||||
|
dj->ev = -1;
|
||||||
|
#if PRETTY
|
||||||
|
snprinth(dj->sv, sizeof(dj->s), dj->s);
|
||||||
|
snprinth(dj->ev, sizeof(dj->e), dj->e);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#if DBG
|
||||||
|
print("FOR: "); printd(dis); print(" "); printd(die); print("\n");
|
||||||
|
print(" "); printd(dj->sv); print(" "); printd(dj->ev); print("\n");
|
||||||
|
print(" -> "); printd(djs); print(" "); printd(dje); print("\n");
|
||||||
|
#endif
|
||||||
|
dj->sv = djs;
|
||||||
|
dj->ev = dje;
|
||||||
|
#if PRETTY
|
||||||
|
snprinth(dj->sv, sizeof(dj->s), dj->s);
|
||||||
|
snprinth(dj->ev, sizeof(dj->e), dj->e);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (struct line *di = ranges; di->sv; di++) {
|
||||||
|
if (di->sv == -1) continue;
|
||||||
|
unsigned long dis = bcdtonum(di->sv);
|
||||||
|
unsigned long die = bcdtonum(di->ev);
|
||||||
|
result += die - dis + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RUN_TEST1 1
|
||||||
|
#define RUN_PART1 1
|
||||||
|
#define RUN_TEST2 1
|
||||||
|
#define RUN_PART2 1
|
||||||
|
|
||||||
|
#define TEST1_EXPECT 3
|
||||||
|
#define TEST2_EXPECT 14
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
#if RUN_TEST1
|
||||||
|
print("PART 1 TEST: ");
|
||||||
|
if (unsigned long v = do_part1(countof(test), test); v != TEST1_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST1_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART1
|
||||||
|
print("PART 1 RESULT: ");
|
||||||
|
printd(do_part1(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_TEST2
|
||||||
|
print("PART 2 TEST: ");
|
||||||
|
if (unsigned long v = do_part2(countof(test), test); v != TEST2_EXPECT) {
|
||||||
|
print("FAILED (got ");
|
||||||
|
printd(v);
|
||||||
|
print(", expected " xstr(TEST2_EXPECT) ")\n");
|
||||||
|
} else {
|
||||||
|
print("PASSED\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RUN_PART2
|
||||||
|
print("PART 2 RESULT: ");
|
||||||
|
printd(do_part2(countof(input), input));
|
||||||
|
print("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
exit_group(0);
|
||||||
|
}
|
||||||
85
lib.h
85
lib.h
@@ -34,6 +34,7 @@ void exit_group(uint64_t code) {
|
|||||||
#define str(s) #s
|
#define str(s) #s
|
||||||
|
|
||||||
typedef uint64_t bcdint;
|
typedef uint64_t bcdint;
|
||||||
|
typedef uint64_t num;
|
||||||
|
|
||||||
static
|
static
|
||||||
void printns(size_t len, unsigned char chars[len]) {
|
void printns(size_t len, unsigned char chars[len]) {
|
||||||
@@ -81,6 +82,23 @@ void printd(unsigned long v) {
|
|||||||
write(STDOUT_FILENO, p, count);
|
write(STDOUT_FILENO, p, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void snprintd(unsigned long v, size_t n, unsigned char d[n]) {
|
||||||
|
memset(d, 0, n);
|
||||||
|
if (!v) {
|
||||||
|
d[n-1] = '0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unsigned char *p = d+n;
|
||||||
|
unsigned count = 0;
|
||||||
|
while (v) {
|
||||||
|
p--;
|
||||||
|
*p = '0' + (v % 10);
|
||||||
|
v /= 10;
|
||||||
|
if (p == d) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void printh(unsigned long v) {
|
void printh(unsigned long v) {
|
||||||
if (!v) {
|
if (!v) {
|
||||||
@@ -103,6 +121,28 @@ void printh(unsigned long v) {
|
|||||||
write(STDOUT_FILENO, p, count);
|
write(STDOUT_FILENO, p, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void snprinth(unsigned long v, size_t n, unsigned char d[n]) {
|
||||||
|
memset(d, 0, n);
|
||||||
|
if (!v) {
|
||||||
|
d[n-1] = '0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unsigned char *p = d+n;
|
||||||
|
unsigned count = 0;
|
||||||
|
while (v) {
|
||||||
|
p--;
|
||||||
|
if ((v & 0x0F) < 0xA) {
|
||||||
|
*p = '0' + (v & 0x0F);
|
||||||
|
} else {
|
||||||
|
*p = 'A' - 0xA + (v & 0x0F);
|
||||||
|
}
|
||||||
|
v >>= 4;
|
||||||
|
if (p == d) return;
|
||||||
|
}
|
||||||
|
while (p >= d) *p-- = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void print_hex_char(unsigned char v) {
|
void print_hex_char(unsigned char v) {
|
||||||
char buf[2];
|
char buf[2];
|
||||||
@@ -169,3 +209,48 @@ static bcdint bcdadd(bcdint a, bcdint b) {
|
|||||||
t2 = (t2 >> 2) | (t2 >> 3);
|
t2 = (t2 >> 2) | (t2 >> 3);
|
||||||
return t1 - t2;
|
return t1 - t2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://homepage.cs.uiowa.edu/~jones/bcd/bcd.html
|
||||||
|
static bcdint bcdcomp(bcdint a) {
|
||||||
|
bcdint t1, t2, t3, t4, t5, t6;
|
||||||
|
t1 = 0xFFFFFFFFFFFFFFFF - a;
|
||||||
|
t2 = - a;
|
||||||
|
t3 = t1 ^ 0x0000000000000001;
|
||||||
|
t4 = t2 ^ t3;
|
||||||
|
t5 = ~t4 & 0x1111111111111110;
|
||||||
|
t6 = (t5 >> 2) | (t5 >> 3);
|
||||||
|
return t2 - t6;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bcdint bcdsub(bcdint a, bcdint b) {
|
||||||
|
return bcdadd(a, bcdcomp(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
static num bcdtonum(bcdint a) {
|
||||||
|
return 0
|
||||||
|
+ ((a >> 0) & 0xF) * 1
|
||||||
|
+ ((a >> 4) & 0xF) * 10
|
||||||
|
+ ((a >> 8) & 0xF) * 100
|
||||||
|
+ ((a >> 12) & 0xF) * 1000
|
||||||
|
+ ((a >> 16) & 0xF) * 10000
|
||||||
|
+ ((a >> 24) & 0xF) * 100000
|
||||||
|
+ ((a >> 28) & 0xF) * 1000000
|
||||||
|
+ ((a >> 32) & 0xF) * 10000000
|
||||||
|
+ ((a >> 36) & 0xF) * 100000000
|
||||||
|
+ ((a >> 40) & 0xF) * 1000000000
|
||||||
|
+ ((a >> 44) & 0xF) * 10000000000
|
||||||
|
+ ((a >> 48) & 0xF) * 100000000000
|
||||||
|
+ ((a >> 52) & 0xF) * 1000000000000
|
||||||
|
+ ((a >> 56) & 0xF) * 10000000000000
|
||||||
|
+ ((a >> 60) & 0xF) * 100000000000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bcdint numtobcd(num a) {
|
||||||
|
bcdint r = 0;
|
||||||
|
while (a) {
|
||||||
|
r <<= 4;
|
||||||
|
r |= (a % 10);
|
||||||
|
a /= 10;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user