solve_day24 :: (test: bool) {
contents := read_entire_file(ifx test then "inputs/day24_test.txt" else "inputs/day24.txt");
lines := split(contents, cast(u8) #char "\n");
valley := parse_valley(lines);
start := Vec2.{ x = 0, y = -1 };
end := Vec2.{ x = valley.boundry.x - 1, y = valley.boundry.y };
part1 := find_exit(valley, start, end);
part2 := find_exit(valley, end, start);
part2 += find_exit(valley, start, end);
part2 += part1;
print("Part 1: %\n", part1);
print("Part 2: %\n", part2);
}
#scope_file
Valley :: struct {
blizzards: [..]Blizzard;
boundry: Vec2;
}
parse_valley :: (lines: []string) -> Valley {
valley: Valley;
valley.boundry.x = lines[0].count - 2;
valley.boundry.y = lines.count - 2;
for line, y: lines {
for 0..line.count - 1 {
if line[it] == {
case #char "v"; array_add(*valley.blizzards, .{ pos = .{ x = it - 1, y = y - 1 }, dir = .{ x = 0, y = 1 }});
case #char ">"; array_add(*valley.blizzards, .{ pos = .{ x = it - 1, y = y - 1 }, dir = .{ x = 1, y = 0 }});
case #char "<"; array_add(*valley.blizzards, .{ pos = .{ x = it - 1, y = y - 1 }, dir = .{ x = -1, y = 0 }});
case #char "^"; array_add(*valley.blizzards, .{ pos = .{ x = it - 1, y = y - 1 }, dir = .{ x = 0, y = -1 }});
}
}
}
return valley;
}
tick :: (valley: Valley) {
for *valley.blizzards {
it.pos += it.dir;
it.pos.x = (it.pos.x + valley.boundry.x) % valley.boundry.x;
it.pos.y = (it.pos.y + valley.boundry.y) % valley.boundry.y;
}
}
is_safe :: (valley: Valley, pos: Vec2) -> bool {
for valley.blizzards {
if pos.x == it.pos.x && pos.y == it.pos.y return false;
}
return true;
}
is_inside :: (valley: Valley, pos: Vec2) -> bool {
if (pos.x == 0 && pos.y == -1) || (pos.x == valley.boundry.x - 1 && pos.y == valley.boundry.y) return true;
return pos.x >= 0 && pos.y >= 0 && pos.x < valley.boundry.x && pos.y < valley.boundry.y;
}
find_exit :: (valley: Valley, start: Vec2, exit: Vec2) -> s64 {
now_t: Table(u64, Vec2);
next_t: Table(u64, Vec2);
defer deinit(*now_t);
defer deinit(*next_t);
table_set(*now_t, convert(start), start);
steps := 0;
while true {
steps += 1;
tick(valley);
for n, k: now_t {
for dir: Vec2.[.{1,0},.{-1,0},.{0,1},.{0,-1},.{0,0}] {
next_pos := n + dir;
if is_inside(valley, next_pos) && is_safe(valley, next_pos) {
if next_pos.x == exit.x && next_pos.y == exit.y return steps;
table_set(*next_t, convert(next_pos), next_pos);
}
}
}
now_t, next_t = next_t, now_t;
table_reset(*next_t);
assert(now_t.count > 0);
print("%\n", now_t.count);
}
return -1;
}
Blizzard :: struct {
dir: Vec2;
pos: Vec2;
}
Vec2 :: struct {
x: s64;
y: s64;
}
operator + :: (v1: Vec2, v2: Vec2) -> Vec2 {
return .{ x = v1.x + v2.x, y = v1.y + v2.y };
}
convert :: (v: Vec2) -> u64 {
return ((cast(u64)v.x) << 32) | (cast(u64)v.y);
}