159 lines
3.8 KiB
C

#include <stdint.h>
#include "parse.h"
#include "printf.h"
#include "cartesian.h"
#include "array.h"
struct position {
char x;
char y;
};
struct antenna {
struct position position[8];
char count;
};
#define FIRST_ANTENNA '0'
#define LAST_ANTENNA 'z'
#define ANTENNA_TYPES ((LAST_ANTENNA - FIRST_ANTENNA) + 1)
void parse_antennas(const char * input, int length, struct antenna * antennas)
{
int x = 0;
int y = 0;
for (int i = 0; i < length; i++) {
char c = input[i];
if (c >= FIRST_ANTENNA && c <= LAST_ANTENNA) {
struct antenna * ant = &antennas[c - FIRST_ANTENNA];
ant->position[ant->count++] = (struct position){x, y};
}
if (c == '\n') {
x = 0;
y += 1;
} else {
x += 1;
}
}
}
struct position vector(struct position a, struct position b)
{
return (struct position){b.x - a.x, b.y - a.y};
}
void part1_antinodes(int width, int height,
struct position p1, struct position p2,
char * antinodes)
{
struct position slope = vector(p1, p2);
struct position a[2] = {
{
p1.x - slope.x,
p1.y - slope.y,
},
{
p2.x + slope.x,
p2.y + slope.y,
}
};
for (int k = 0; k < 2; k++) {
if (cartesian_inside(width, height, a[k].x, a[k].y)) {
antinodes[a[k].y * width + a[k].x] = 1;
}
}
}
void interpolate_antinodes(int width,
int height,
struct position ant,
struct position slope,
char * antinodes)
{
int x = ant.x;
int y = ant.y;
while (true) {
if (!cartesian_inside(width, height, x, y))
break;
antinodes[y * width + x] = 1;
x -= slope.x;
y -= slope.y;
}
}
void part2_antinodes(int width, int height,
struct position p1, struct position p2,
char * antinodes)
{
struct position slope = vector(p1, p2);
interpolate_antinodes(width, height, p1, (struct position){-slope.x, -slope.y}, antinodes);
interpolate_antinodes(width, height, p2, (struct position){ slope.x, slope.y}, antinodes);
}
typedef void (* part_solver)(int width, int height,
struct position p1, struct position p2,
char * antinodes);
void find_antinodes(int width, int height,
const struct antenna * antennas,
char * antinodes,
part_solver func)
{
for (int t = FIRST_ANTENNA; t <= LAST_ANTENNA; t++) {
const struct antenna * ant = &antennas[t - FIRST_ANTENNA];
for (int i = 0; i < ant->count; i++) {
for (int j = i + 1; j < ant->count; j++) {
func(width, height,
ant->position[i], ant->position[j],
antinodes);
}
}
}
}
int64_t _2024_day8_part1(const char * input, int length)
{
int stride = parse_stride(input, length);
int height = parse_height(input, length);
int width = stride - 1;
struct antenna antennas[ANTENNA_TYPES];
for (int i = 0; i < ANTENNA_TYPES; i++)
antennas[i].count = 0;
char antinodes[width * height];
for (int i = 0; i < width * height; i++)
antinodes[i] = 0;
parse_antennas(input, length, antennas);
find_antinodes(width, height, antennas, antinodes, part1_antinodes);
return array_sum_char(antinodes, width * height);
}
int64_t _2024_day8_part2(const char * input, int length)
{
int stride = parse_stride(input, length);
int height = parse_height(input, length);
int width = stride - 1;
struct antenna antennas[ANTENNA_TYPES];
for (int i = 0; i < ANTENNA_TYPES; i++)
antennas[i].count = 0;
char antinodes[width * height];
for (int i = 0; i < width * height; i++)
antinodes[i] = 0;
parse_antennas(input, length, antennas);
find_antinodes(width, height, antennas, antinodes, part2_antinodes);
return array_sum_char(antinodes, width * height);
}