diff --git a/day2.c b/day2.c index 5004e81..edb3524 100644 --- a/day2.c +++ b/day2.c @@ -249,10 +249,10 @@ no_len_change: return result; } -#define RUN_TEST1 1 -#define RUN_PART1 1 +#define RUN_TEST1 0 +#define RUN_PART1 0 #define RUN_TEST2 0 -#define RUN_PART2 0 +#define RUN_PART2 1 #define TEST1_EXPECT 0x1227775554l #define TEST2_EXPECT 0x4174379265l diff --git a/day2opt.c b/day2opt.c new file mode 100644 index 0000000..ea4e49c --- /dev/null +++ b/day2opt.c @@ -0,0 +1,257 @@ +#include "lib.h" + +#define DBG 0 + +static +alignas(0x40) unsigned char input[] = { +#embed "day2_input.txt" +}; + +struct id { + size_t len; + bcdint v; +}; + +static +bcdint next_palindrome_len2(bcdint in) { + bcdint low = in & 0xF; + bcdint high = in >> 4; + + bcdint higher = high + 1; + + bcdint high_pd = 0x11 * high; + bcdint higher_pd = 0x11 * higher; + + return low > high ? higher_pd : high_pd; +} + +static +bcdint next_palindrome_len3(bcdint in) { + bcdint nib0 = in & 0xF; + bcdint nib1 = (in >> 4) & 0xF; + bcdint high = in >> 8; + + bcdint higher = high + 1; + + bcdint high_pd = 0x111 * high; + bcdint higher_pd = 0x111 * higher; + + if (nib1 < high) return high_pd; + return nib0 > high ? higher_pd : high_pd; +} + +static +bcdint next_palindrome_len4(bcdint in) { + bcdint nib0 = in & 0xF; + bcdint nib1 = (in >> 4) & 0xF; + bcdint nib2 = (in >> 8) & 0xF; + bcdint nib3 = in >> 12; + + bcdint nib3er = nib3 + 1; + + bcdint nib3_pd = 0x1111 * nib3; + bcdint nib3er_pd = 0x1111 * nib3er; + + bcdint nib10 = in & 0xFF; + bcdint nib32 = in >> 8; + + bcdint nib32er = bcdadd(nib32, 1); + + bcdint nib32_pd = 0x0101 * nib32; + bcdint nib32er_pd = 0x0101 * nib32er; + + bcdint r = nib3er_pd; + if (nib3_pd > in) r = nib3_pd; + if (nib32er_pd > in) r = nib32er_pd; + if (nib32_pd > in) r = nib32_pd; + + return r; +} + +static +bcdint next_palindrome_len6(bcdint in) { + bcdint nib0 = in & 0xF; + bcdint nib1 = (in >> 4) & 0xF; + bcdint nib2 = (in >> 8) & 0xF; + bcdint nib3 = (in >> 12) & 0xF; + bcdint nib4 = (in >> 16) & 0xF; + bcdint nib5 = in >> 20; + + bcdint nib5er = nib5 + 1; + + bcdint nib5_pd = 0x111111 * nib5; + bcdint nib5er_pd = 0x111111 * nib5er; + + bcdint nib10 = in & 0xFF; + bcdint nib32 = (in >> 8) & 0xFF; + bcdint nib54 = in >> 16; + + bcdint nib54er = bcdadd(nib54, 1); + + bcdint nib54_pd = 0x010101 * nib54; + bcdint nib54er_pd = 0x010101 * nib54er; + + bcdint nib210 = in & 0xFFF; + bcdint nib543 = in >> 12; + + bcdint nib543er = bcdadd(nib543, 1); + + bcdint nib543_pd = 0x001001 * nib543; + bcdint nib543er_pd = 0x001001 * nib543er; + + bcdint r = nib5er_pd; + if (nib5_pd > in) r = MIN(r,nib5_pd); + if (nib54er_pd > in) r = MIN(r,nib54er_pd); + if (nib54_pd > in) r = MIN(r,nib54_pd); + if (nib543er_pd > in) r = MIN(r,nib543er_pd); + if (nib543_pd > in) r = MIN(r,nib543_pd); + + return r; +} + +static +bcdint next_palindrome_len8(bcdint in) { + bcdint nib0 = in & 0xF; + bcdint nib1 = (in >> 4) & 0xF; + bcdint nib2 = (in >> 8) & 0xF; + bcdint nib3 = (in >> 12) & 0xF; + bcdint nib4 = (in >> 16) & 0xF; + bcdint nib5 = (in >> 20) & 0xF; + bcdint nib6 = (in >> 24) & 0xF; + bcdint nib7 = in >> 28; + + bcdint nib7er = nib7 + 1; + + bcdint nib7_pd = 0x11111111 * nib7; + bcdint nib7er_pd = 0x11111111 * nib7er; + + bcdint nib10 = in & 0xFF; + bcdint nib32 = (in >> 8) & 0xFF; + bcdint nib54 = (in >> 16) & 0xFF; + bcdint nib76 = in >> 24; + + bcdint nib76er = bcdadd(nib76, 1); + + bcdint nib76_pd = 0x01010101 * nib76; + bcdint nib76er_pd = 0x01010101 * nib76er; + + bcdint nib3210 = in & 0xFFFF; + bcdint nib7654 = in >> 16; + + bcdint nib7654er = bcdadd(nib7654, 1); + + bcdint nib7654_pd = 0x00010001 * nib7654; + bcdint nib7654er_pd = 0x00010001 * nib7654er; + + bcdint r = nib7er_pd; + if (nib7_pd > in) r = MIN(r,nib7_pd); + if (nib76er_pd > in) r = MIN(r,nib76er_pd); + if (nib76_pd > in) r = MIN(r,nib76_pd); + if (nib7654er_pd > in) r = MIN(r,nib7654er_pd); + if (nib7654_pd > in) r = MIN(r,nib7654_pd); + + return r; +} + +static +bcdint next_palindrome_part2(struct id s) { + if (s.len == 2) return next_palindrome_len2(s.v); + else if (s.len == 3) return next_palindrome_len3(s.v); + else if (s.len == 4) return next_palindrome_len4(s.v); + else if (s.len == 6) return next_palindrome_len6(s.v); + else if (s.len == 8) return next_palindrome_len8(s.v); + + unsigned len = s.len; + bcdint in = s.v; + + bcdint best = -1; + for (unsigned i = 2; i <= len; i++) { + if (len % i == 0) { + unsigned high_shift = (len / i) * 4; + + bcdint high = in >> (high_shift * (i - 1)); + + for (int j = i - 2; j >= 0; j--) { + bcdint low = (in >> (high_shift * (j))) & ((1 << high_shift) - 1); + + if (low < high) { + break; + } else if (low > high) { + high = bcdadd(high, 1); + break; + } + } + + bcdint next = 0; + for (unsigned j = 0; j < i; j++) { + next |= high << (high_shift * j); + } + + if (next < best) { + best = next; + } + } + } + + return best; +} + +static +bcdint do_part2(size_t file_len, unsigned char file[file_len]) { + unsigned char *src = file; + bcdint result = 0; + + alignas(0x40) struct id ranges[128]; + size_t range_count = 0; + + do { + unsigned char *tmp; + bcdint rs = grabbcd(src, &tmp); + ranges[range_count * 2 + 0] = (struct id) { + .len = tmp - src, + .v = rs + }; + src = tmp + 1; + + bcdint re = grabbcd(src, &tmp); + ranges[range_count * 2 + 1] = (struct id) { + .v = re + }; + src = tmp + 1; + + range_count++; + } while (src != &file[file_len]); + + do { + range_count--; + struct id next = ranges[range_count * 2 + 0]; + bcdint re = ranges[range_count * 2 + 1].v; + do { + if (next.len == 1) { + next = (struct id) { .len = 2, .v = 0x11 }; + } else { + next.v = next_palindrome_part2(next); + } + if (next.v <= re) { + result = bcdadd(result, next.v); + } + bcdint tmp = bcdadd(next.v, 1); + for (bcdint chk = next.v; chk > 0; chk >>= 4) { + if ((chk & 0xF) != 9) goto no_len_change; + } + next.len++; + no_len_change: + next.v = tmp; + } while (next.v <= re); + } while (range_count); + + return result; +} + +void run() { + print("PART 2 RESULT: "); + printh(do_part2(countof(input), input)); + print("\n"); + + exit_group(0); +} diff --git a/lib.h b/lib.h index 0f0aac9..1f97976 100644 --- a/lib.h +++ b/lib.h @@ -27,6 +27,9 @@ void exit_group(uint64_t code) { for (;;); } +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) + #define xstr(s) str(s) #define str(s) #s