133 lines
3.1 KiB
C
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;
|
|
}
|