dummy_void: void;
solve_day12 :: (test: bool) {
contents := read_entire_file(ifx test then "inputs/day12_test.txt" else "inputs/day12.txt");
lines := split(contents, cast(u8) #char "\n");
builder: String_Builder;
grid: Grid;
grid.height = lines.count;
grid.width = lines[0].count;
for lines {
print_to_builder(*builder, it);
}
grid.grid = builder_to_string(*builder);
end: Coord;
start: Coord;
start.height = #char "a";
for lines {
start_index := find_index_from_left(it, cast(u8) #char "S");
end_index := find_index_from_left(it, cast(u8) #char "E");
if start_index != -1 {
start.x = start_index;
start.y = it_index;
}
if end_index != -1 {
end.x = end_index;
end.y = it_index;
}
}
visited: Table(s64, Coord);
grid.grid[end.y * grid.width + end.x] = #char "z";
grid.grid[start.y * grid.width + start.x] = #char "a";
part1 := find_shortest_path(start, end, grid, S64_MAX, *visited);
part2 := part1;
for x: 0..grid.width - 1 {
for y: 0..grid.height - 1 {
if grid.grid[grid.width * y + x] == #char "a" {
start.x = x;
start.y = y;
part2 = find_shortest_path(start, end, grid, part2, *visited);
}
}
}
print("Part 1: %\n", part1);
print("Part 2: %\n", part2);
}
find_shortest_path :: (start: Coord, end: Coord, grid: Grid, shorter_than: s64, visited: *Table) -> s64 {
queue: Priority_Queue(Coord, (a, b) => a.steps - b.steps);
init(*queue);
add(*queue, start);
length := shorter_than;
dummy_: [..]Coord;
dirs := Coord.[.{1,0,0,0, dummy_}, .{-1,0,0,1, dummy_}, .{0,1,0,2, dummy_}, .{0,-1,0,3, dummy_}];
final_pos: Coord = ---;
while outer:= queue.count > 0 {
removed,item := remove_top(*queue);
defer array_free(item.visited);
for dir: dirs {
new_pos := item + dir;
new_pos.steps += 1;
if new_pos.steps > shorter_than continue;
visited_item, found_visited := table_find(visited, convert_to_s64(new_pos));
if !inside(new_pos, grid) || (found_visited && new_pos.steps >= visited_item.steps) continue;
new_pos.height = grid.grid[new_pos.y * grid.width + new_pos.x];
if new_pos.height <= item.height + 1 {
array_copy(*new_pos.visited, item.visited);
array_add(*new_pos.visited, new_pos);
if new_pos.x == end.x && new_pos.y == end.y {
length = new_pos.steps;
final_pos = new_pos;
break outer;
}
table_set(visited, convert_to_s64(new_pos), new_pos);
add(*queue, new_pos);
}
}
}
while queue.count > 0 {
removed, item := remove_top(*queue);
array_free(item.visited);
}
return length;
}
convert_to_arrow :: (from: Coord, to: Coord) -> u8 {
g := from - to;
if g.x == -1 return #char ">";
if g.x == 1 return #char "<";
if g.y == -1 return #char "v";
if g.y == 1 return #char "^";
return #char "?";
}
convert_to_s64 :: (c: Coord) -> s64 {
result := (cast,no_check(u64)c.x) << 32 | cast(u64)(cast,no_check(u32)c.y);
return cast,no_check(s64)result;
}
inside :: (pos: Coord, grid: Grid) -> bool {
return pos.x >= 0 && pos.x < grid.width && pos.y >= 0 && pos.y < grid.height;
}
#scope_file
Coord :: struct {
x: s64;
y: s64;
height: s64;
steps: s64;
visited: [..]Coord;
}
operator - :: (c1: Coord, c2: Coord) -> Coord {
dummy: [..]Coord;
return .{ c1.x - c2.x, c1.y - c2.y, c1.height, c1.steps, dummy };
}
operator + :: (c1: Coord, c2: Coord) -> Coord {
dummy: [..]Coord;
return .{ c1.x + c2.x, c1.y + c2.y, c1.height, c1.steps, dummy };
}