#define RT_CORE_IMPLEMENTATION #include "rtcore.h" #include "aoc.h" #include typedef struct { i64 first; i64 last; } range; i64 S8ToInt(s8 s, int base) { isize at = s.length - 1; i64 exp = 1; i64 val = 0; while (at >= 0) { u8 c = s.data[at]; int digit = 0; if (c >= '0' && c <= '9') digit = c - '0'; else if (c >= 'A' && c <= 'Z') digit = c - 'A'; else if (c >= 'a' && c <= 'z') digit = c - 'a'; else if (c == '-') { val *= -1; break; } else if (c == '+') { break; } else return 0; val += digit * exp; exp *= base; --at; } return val; } internal int NumberOfDigits(i64 v) { return (int)floor(log10((double)v)) + 1; } int main(int argc, char **argv) { arena arena = CreateArena(); dataset ds = ParseDatasetOption(argc, argv); s8 input = {0}; if (ds == DS_FULL) input = ReadEntireFileS8(S8("inputs/day02_full"), &arena); else if (ds == DS_DEMO) input = ReadEntireFileS8(S8("inputs/day02_demo"), &arena); if (!input.data) return 1; /* First parse the ranges. */ split_result split = S8Split(input, ','); range *ranges = (range *)arena.begin; isize num_ranges = 0; while (split.first.data) { split_result range_str = S8Split(split.first, '-'); range range = {0}; range.first = S8ToInt(range_str.first, 10); range.last = S8ToInt(S8TrimRight(range_str.second), 10); ranges[num_ranges++] = range; split = S8Split(split.second, ','); } arena.begin += sizeof(range) * num_ranges; /* We can generate numbers that consist of 2 repeating sequences with: * (10**n + 1) * m (with m < 10**n) * * For a number with k digits, n is k / 2 * ex. 123123 has k=6 digits, which gives n = 3 * and obviously m = 123 * => (10**3 + 1) * 123 = 1001 * 123 = 123123 * * Now we can step through every (m,n) that generates numbers in the current range. */ double sum = 0.0; for (isize range_idx = 0; range_idx < num_ranges; ++range_idx) { int k0 = NumberOfDigits(ranges[range_idx].first); int k1 = NumberOfDigits(ranges[range_idx].last); printf("%ld - %ld -> %d %d\n", ranges[range_idx].first, ranges[range_idx].last, k0, k1); double range_first = (double)ranges[range_idx].first; double range_last = (double)ranges[range_idx].last; for (int k = k0; k <= k1; ++k) { if ((k % 2) != 0) continue; double n = (double)k / 2; double fac = pow(10.0, n) + 1.0; double max_m = pow(10.0, (double)n); double min_m = pow(10, (double)n - 1); double m_from_range = ceil(range_first / fac); min_m = max(min_m, m_from_range); printf("For k=%d we get n=%lf min_m = %lf max_m = %lf, m_from_range = %lf\n", k, n, min_m, max_m, m_from_range); for (double m = min_m; m < max_m; m += 1.0) { double id = fac * m; if (id >= range_first && id <= range_last) { printf("Invalid id: %lf\n", id); sum += id; } if (id > range_last) break; } } } printf("Answer: %lf\n", sum); return 0; }