solve_day15 :: (test: bool) {
contents := read_entire_file(ifx test then "inputs/day15_test.txt" else "inputs/day15.txt");
lines := split(contents, cast(u8) #char "\n");
sensors: [..]Sensor;
row := ifx test then 10 else 2_000_000;
intervals: [..]Interval;
for line: lines {
equals_split := split(line, cast(u8) #char "=");
beacon_x := string_to_int(slice(equals_split[3], 0, find_index_from_left(equals_split[3], cast(u8) #char ",")), 10, s64);
beacon_y := string_to_int(slice(equals_split[4], 0, equals_split[4].count), 10, s64);
sensor: = Sensor.{
x = string_to_int(slice(equals_split[1], 0, find_index_from_left(equals_split[1], cast(u8) #char ",")), 10, s64),
y = string_to_int(slice(equals_split[2], 0, find_index_from_left(equals_split[2], cast(u8) #char ":")), 10, s64),
};
sensor.closest = abs(beacon_x - sensor.x) + abs(beacon_y - sensor.y);
array_add(*sensors, sensor);
interval := Interval.{
start = sensor.x - (sensor.closest - abs(row - sensor.y)),
end = sensor.x + (sensor.closest - abs(row - sensor.y)),
};
if interval.start > interval.end {
interval.start, interval.end = interval.end, interval.start;
}
insert_interval(*intervals, interval);
}
part1 := 0;
part2 := 0;
for intervals {
part1 += it.end - it.start;
}
max_dim := ifx test then 20 else 4_000_000;
for s1: 0..sensors.count - 1 {
for s2: s1 + 1..sensors.count - 1 {
d := dist(sensors[s1].pos, sensors[s2].pos);
if sensors[s1].closest + sensors[s2].closest + 2 == dist(sensors[s1].pos, sensors[s2].pos) {
_s1 := sensors[s1];
_s2 := sensors[s2];
if _s1.x > _s2.x _s1, _s2 = _s2, _s1;
for _x: -_s1.closest - 1.._s1.closest + 1 {
pos := Vec2.{
x = _s1.x + _x,
y = _s1.y + ((_s1.closest + 1) - _x),
};
if dist(pos, .{_s2.x,_s2.y}) == _s2.closest + 1 {
to_remove := false;
for sensor: sensors {
if dist(pos, .{sensor.x, sensor.y}) <= sensor.closest {
to_remove = true;
break;
}
}
if !to_remove {
part2 = pos.x * 4_000_000 + pos.y;
break s1;
}
}
}
}
}
}
print("Part 1: %\n", part1);
print("Part 2: %\n", part2);
}
inside :: (point: Vec2, max_dim: s64) -> bool {
return point.x >= 0 && point.x <= max_dim &&
point.y >= 0 && point.y <= max_dim;
}
dist :: (v1: Vec2, v2: Vec2) -> s64 {
return abs(v1.x - v2.x) + abs(v1.y - v2.y);
}
insert_interval :: (intervals: *[..]Interval, interval: Interval) {
array_add(intervals, interval);
collapse_intervals(intervals);
}
collapse_intervals :: (intervals: *[..]Interval) {
while m := true {
for *f, f_index: (<< intervals) {
for f_index + 1..intervals.count - 1 {
if ((<< intervals)[it].start <= f.start && (<< intervals)[it].end >= f.start) ||
((<< intervals)[it].start <= f.end && (<< intervals)[it].end >= f.end) ||
((<< intervals)[it].start >= f.start && (<< intervals)[it].start <= f.end) {
f.start = min(f.start, (<< intervals)[it].start);
f.end = max(f.end, (<< intervals)[it].end);
array_unordered_remove_by_index(intervals, it);
continue m;
}
}
}
break m;
}
}
#scope_file
Vec2 :: struct {
x: s64;
y: s64;
}
Interval :: struct {
start: s64;
end: s64;
}
Sensor :: struct {
using pos: Vec2;
closest: s64;
}