128 lines
2.5 KiB
C
128 lines
2.5 KiB
C
#include <stdbool.h>
|
|
|
|
#include "parse.h"
|
|
#include "printf.h"
|
|
#include "minmax.h"
|
|
|
|
struct rule {
|
|
char l;
|
|
char r;
|
|
};
|
|
|
|
static void error(void)
|
|
{
|
|
printf("day5: invalid input\n");
|
|
while (1);
|
|
}
|
|
|
|
static const char * parse_rules(const char * input, const char * end,
|
|
struct rule * rules, int * rules_length)
|
|
{
|
|
int i = 0;
|
|
|
|
while (input < end) {
|
|
int num;
|
|
input = parse_base10(input, &num);
|
|
if (*input++ != '|') { error(); }
|
|
rules[i].l = num;
|
|
|
|
input = parse_base10(input, &num);
|
|
if (*input++ != '\n') { error(); }
|
|
rules[i].r = num;
|
|
|
|
i += 1;
|
|
|
|
if (*input == '\n')
|
|
break; // end of rules
|
|
}
|
|
|
|
*rules_length = i;
|
|
|
|
return parse_skip(input, '\n');
|
|
}
|
|
|
|
static const char * parse_update(const char * input, const char * end,
|
|
char * update, int * update_length)
|
|
{
|
|
int i = 0;
|
|
while (input < end) {
|
|
int num;
|
|
input = parse_base10(input, &num);
|
|
input = parse_skip(input, ',');
|
|
|
|
update[i] = num;
|
|
i += 1;
|
|
|
|
if (*input == '\n')
|
|
break; // end of update
|
|
}
|
|
|
|
*update_length = i;
|
|
|
|
return parse_skip(input, '\n');
|
|
}
|
|
|
|
static bool rule_match(const struct rule * rule, int a, int b)
|
|
{
|
|
return rule->l == a && rule->r == b;
|
|
}
|
|
|
|
static bool sort_numbers(const struct rule * rules, int rules_length,
|
|
char * nums, int nums_length)
|
|
{
|
|
bool at_least_one_swap = false;
|
|
while (true) {
|
|
bool swapped = false;
|
|
for (int i = 0; i < nums_length - 1; i++) {
|
|
int a = nums[i + 0];
|
|
int b = nums[i + 1];
|
|
|
|
for (int j = 0; j < rules_length; j++) {
|
|
if (rule_match(&rules[j], b, a)) {
|
|
swapped = true;
|
|
at_least_one_swap = true;
|
|
nums[i + 0] = b;
|
|
nums[i + 1] = a;
|
|
}
|
|
}
|
|
}
|
|
if (!swapped)
|
|
break;
|
|
}
|
|
|
|
return at_least_one_swap;
|
|
}
|
|
|
|
static int solve(const char * input, int length, bool correctly_ordered)
|
|
{
|
|
const char * end = input + length;
|
|
|
|
struct rule rules[1200];
|
|
int rules_length;
|
|
input = parse_rules(input, end, rules, &rules_length);
|
|
|
|
int sum = 0;
|
|
char update[24];
|
|
while (input < end) {
|
|
int update_length;
|
|
input = parse_update(input, end, update, &update_length);
|
|
|
|
bool at_least_one_swap = sort_numbers(rules, rules_length, update, update_length);
|
|
if (correctly_ordered ^ at_least_one_swap) {
|
|
sum += update[update_length / 2];
|
|
}
|
|
}
|
|
|
|
return sum;
|
|
}
|
|
|
|
int day5_part1(const char * input, int length)
|
|
{
|
|
return solve(input, length, true);
|
|
}
|
|
|
|
int day5_part2(const char * input, int length)
|
|
{
|
|
return solve(input, length, false);
|
|
}
|