advent-of-sh/2023/day3/_solution.c

217 lines
5.2 KiB
C

#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
extern uint32_t _binary_2023_day3_input_txt_start __asm("_binary_input_txt_start");
extern uint32_t _binary_2023_day3_input_txt_end __asm("_binary_input_txt_end");
uint32_t parse_base10(uint8_t const ** const buf, uint32_t * num)
{
uint8_t const * const start_pos = *buf + 1;
*num = 0;
while (true) {
uint8_t c = *(*buf)++;
if (c >= '0' && c <= '9') {
c = c - '0';
*num = *num * 10 + c;
} else {
/* return number of parsed digits */
return *buf - start_pos;
}
}
}
uint32_t next_number(uint8_t const * const end,
uint8_t const ** const buf,
uint32_t * num)
{
uint32_t digits = 0;
while (digits == 0 && *buf < end)
digits = parse_base10(buf, num);
return digits;
}
uint32_t stride_newline(uint8_t const * const start)
{
uint8_t const * buf = start;
while (*buf++ != '\n');
return buf - start;
}
void xy_from_ix(uint8_t const * const start,
uint8_t const * const buf,
uint32_t const stride,
int32_t * x,
int32_t * y)
{
uint32_t const offset = buf - start;
*y = offset / stride;
*x = offset % stride;
}
bool xy_in_bounds(int32_t const max_x,
int32_t const max_y,
int32_t const x,
int32_t const y)
{
return x >= 0 && y >= 0 && y <= max_y && x <= max_x;
}
uint32_t ix_from_xy(uint8_t const * const start,
uint32_t const stride,
int32_t const x,
int32_t const y)
{
return (stride * y + x);
}
bool is_symbol(uint8_t const c)
{
static uint8_t const symbols[] = {'@', '&', '=', '/', '-', '+', '%', '*', '$', '#'};
for (uint32_t i = 0; i < (sizeof (symbols)) / (sizeof (*symbols)); i++) {
if (c == symbols[i]) {
return true;
}
}
return false;
}
bool is_gear(uint8_t const c)
{
return c == '*';
}
struct adjacency {
uint32_t ix;
int32_t count;
int32_t neighbors[4];
};
int32_t last_gear = 0;
struct adjacency gears[512] = {0};
void update_gear_adjacencies(uint32_t gear_ix, uint32_t num)
{
for (int i = 0; i < (sizeof (gears)) / (sizeof (*gears)); i++) {
if (i >= last_gear) {
gears[last_gear++].ix = gear_ix;
}
if (gears[i].ix == gear_ix) {
if (gears[i].count < 4) {
gears[i].neighbors[gears[i].count++] = num;
}
break;
}
}
}
void adjacency_check(uint8_t const * const start,
uint32_t const stride,
int32_t const max_x,
int32_t const max_y,
int32_t const x,
int32_t const y,
uint32_t const num,
bool * neighbor)
{
if (xy_in_bounds(max_x, max_y, x, y)) {
uint32_t const ix = ix_from_xy(start, stride, x, y);
uint8_t const c = start[ix];
if (is_symbol(c))
*neighbor = true;
if (is_gear(c))
update_gear_adjacencies(ix, num);
}
}
bool has_adjacent_symbol(uint8_t const * const start,
uint32_t const stride,
int32_t const max_x,
int32_t const max_y,
int32_t const x,
int32_t const y,
uint32_t const num,
int32_t const digits
)
{
bool neighbor = false;
/* check top/bottom/diagonals */
for (int32_t xi = x - 1; xi <= x + digits; xi++) {
adjacency_check(start, stride, max_x, max_y, xi, y + 1, num, &neighbor);
adjacency_check(start, stride, max_x, max_y, xi, y - 1, num, &neighbor);
}
/* check left/right side */
adjacency_check(start, stride, max_x, max_y, x + digits, y, num, &neighbor);
adjacency_check(start, stride, max_x, max_y, x - 1 , y, num, &neighbor);
return neighbor;
}
uint64_t part2_mac(void)
{
uint64_t mac = 0;
for (int i = 0; i < last_gear; i++) {
if (gears[i].count == 2) {
mac += (uint64_t)gears[i].neighbors[0] * (uint64_t)gears[i].neighbors[1];
}
}
return mac;
}
void solve(uint8_t const * const start,
uint8_t const * const end,
uint32_t const stride)
{
uint8_t const * buf = start;
int32_t max_x, max_y;
xy_from_ix(start, end - 1, stride, &max_x, &max_y);
uint32_t sum = 0;
while (true) {
uint32_t num, digits;
digits = next_number(end, &buf, &num);
if (digits == 0)
break;
uint8_t const * const num_start = buf - (digits + 1);
int32_t x, y;
xy_from_ix(start, num_start, stride, &x, &y);
const bool has = has_adjacent_symbol(start,
stride,
max_x,
max_y,
x,
y,
num,
(int32_t)digits
);
if (has)
sum += num;
}
printf("part1 sum: %d\n", sum);
printf("part2:\n");
printf(" gears : %d\n", last_gear);
printf(" answer: %ld\n", part2_mac());
}
int main(void)
{
uint8_t const * const start = (uint8_t *)&_binary_2023_day3_input_txt_start;
uint8_t const * const end = (uint8_t *)&_binary_2023_day3_input_txt_end;
uint32_t const stride = stride_newline(start);
solve(start, end, stride);
}