1
0
advent-of-code-2025/day02.c
2025-12-12 11:29:07 +01:00

133 lines
3.1 KiB
C

#define RT_CORE_IMPLEMENTATION
#include "rtcore.h"
#include "aoc.h"
#include <math.h>
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;
}