147 lines
3.3 KiB
C
147 lines
3.3 KiB
C
#include <stdint.h>
|
|
|
|
#include "parse.h"
|
|
#include "printf.h"
|
|
|
|
enum cube_color {
|
|
red = 0,
|
|
green = 1,
|
|
blue = 2,
|
|
};
|
|
|
|
struct cube_set {
|
|
int color[3];
|
|
};
|
|
|
|
static const char * parse_color(const char * input, enum cube_color * color)
|
|
{
|
|
const char * end;
|
|
if ((end = parse_match(input, "red"))) {
|
|
*color = red;
|
|
} else if ((end = parse_match(input, "blue"))) {
|
|
*color = blue;
|
|
} else if ((end = parse_match(input, "green"))) {
|
|
*color = green;
|
|
}
|
|
return end;
|
|
}
|
|
|
|
static const char * parse_cube(const char * input, int * value, enum cube_color * color)
|
|
{
|
|
input = parse_skip(input, ' ');
|
|
input = parse_base10(input, value);
|
|
input = parse_skip(input, ' ');
|
|
input = parse_color(input, color);
|
|
return input;
|
|
}
|
|
|
|
static const char * parse_game(const char * input, int * number)
|
|
{
|
|
input = parse_match(input, "Game ");
|
|
input = parse_base10(input, number);
|
|
input = parse_skip(input, ':');
|
|
|
|
return input;
|
|
}
|
|
|
|
static const char * parse_round(const char * input, struct cube_set * set)
|
|
{
|
|
while (true) {
|
|
int value;
|
|
enum cube_color color;
|
|
input = parse_cube(input, &value, &color);
|
|
set->color[color] = value;
|
|
if (*input != ',')
|
|
break;
|
|
input++;
|
|
}
|
|
return input;
|
|
}
|
|
|
|
static void part1_set(const struct cube_set * set, void * data)
|
|
{
|
|
bool * valid = data;
|
|
bool v = set->color[red] <= 12 && set->color[green] <= 13 && set->color[blue] <= 14;
|
|
*valid &= v;
|
|
}
|
|
|
|
static int part1_sum(int game_number, void * data)
|
|
{
|
|
bool * valid = data;
|
|
int res = ((int)*valid) * game_number;
|
|
*valid = true;
|
|
return res;
|
|
}
|
|
|
|
static void part2_set(const struct cube_set * set, void * data)
|
|
{
|
|
struct cube_set * max_set = data;
|
|
if (max_set->color[red] < set->color[red])
|
|
max_set->color[red] = set->color[red];
|
|
if (max_set->color[green] < set->color[green])
|
|
max_set->color[green] = set->color[green];
|
|
if (max_set->color[blue] < set->color[blue])
|
|
max_set->color[blue] = set->color[blue];
|
|
}
|
|
|
|
static int part2_sum(int game_number, void * data)
|
|
{
|
|
struct cube_set * set = data;
|
|
int res = set->color[red] * set->color[green] * set->color[blue];
|
|
set->color[red] = 0; set->color[green] = 0; set->color[blue] = 0;
|
|
return res;
|
|
}
|
|
|
|
typedef void (* part_set_func)(const struct cube_set * set, void * data);
|
|
typedef int (* part_sum_func)(int game_number, void * data);
|
|
|
|
static int solve(const char * input, int length, part_set_func part_set, part_sum_func part_sum, void * data)
|
|
{
|
|
const char * end = input + length;
|
|
|
|
int game_number;
|
|
|
|
int sum = 0;
|
|
|
|
while (input < end) {
|
|
input = parse_game(input, &game_number);
|
|
|
|
struct cube_set set;
|
|
|
|
while (true) {
|
|
set.color[red] = 0; set.color[green] = 0; set.color[blue] = 0;
|
|
input = parse_round(input, &set);
|
|
|
|
part_set(&set, data);
|
|
|
|
if (*input != ';')
|
|
break;
|
|
input++;
|
|
}
|
|
|
|
int next_sum = sum + part_sum(game_number, data);
|
|
if (next_sum < sum)
|
|
printf("overflow\n");
|
|
sum = next_sum;
|
|
|
|
input = parse_skip(input, '\n');
|
|
}
|
|
|
|
return sum;
|
|
}
|
|
|
|
int64_t _2023_day2_part1(const char * input, int length)
|
|
{
|
|
bool valid = true;
|
|
|
|
return solve(input, length, part1_set, part1_sum, (void *)&valid);
|
|
}
|
|
|
|
int64_t _2023_day2_part2(const char * input, int length)
|
|
{
|
|
struct cube_set set;
|
|
set.color[red] = 0; set.color[green] = 0; set.color[blue] = 0;
|
|
|
|
return solve(input, length, part2_set, part2_sum, (void *)&set);
|
|
}
|