Files
aoc2025/day2opt.c

258 lines
6.2 KiB
C

#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);
}