From fda2b0d523b1ae096a86d1119ea05af7490a0f06 Mon Sep 17 00:00:00 2001 From: Lucia Ceionia Date: Fri, 5 Dec 2025 01:31:39 -0600 Subject: [PATCH] day 5, pretty blinkenlights mem, awful performance --- day5.c | 230 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib.h | 85 +++++++++++++++++++++ 2 files changed, 315 insertions(+) create mode 100644 day5.c diff --git a/day5.c b/day5.c new file mode 100644 index 0000000..6768d31 --- /dev/null +++ b/day5.c @@ -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); +} diff --git a/lib.h b/lib.h index 1f97976..0101e4c 100644 --- a/lib.h +++ b/lib.h @@ -34,6 +34,7 @@ void exit_group(uint64_t code) { #define str(s) #s typedef uint64_t bcdint; +typedef uint64_t num; static void printns(size_t len, unsigned char chars[len]) { @@ -81,6 +82,23 @@ void printd(unsigned long v) { 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 void printh(unsigned long v) { if (!v) { @@ -103,6 +121,28 @@ void printh(unsigned long v) { 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 void print_hex_char(unsigned char v) { char buf[2]; @@ -169,3 +209,48 @@ static bcdint bcdadd(bcdint a, bcdint b) { t2 = (t2 >> 2) | (t2 >> 3); 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; +}