aoc/day9/src/main.zig

144 lines
4.4 KiB
Zig

const std = @import("std");
pub fn main() anyerror!void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const alloc = &arena.allocator;
// Read our input
var f = try std.fs.cwd().openFile("input", .{});
defer f.close();
var contents = try f.readToEndAlloc(alloc, std.math.maxInt(u32));
defer alloc.free(contents);
var x: usize = 0;
var y: usize = 0;
var it = std.mem.tokenize(contents, "\n");
while (it.next()) |l| {
x = l.len;
y += 1;
}
std.log.debug("Map is {}, {}", .{x, y});
const width = x;
const height = y;
var map = try alloc.alloc(u8, x * y);
defer alloc.free(map);
it = std.mem.tokenize(contents, "\n");
y = 0;
while (it.next()) |line| {
x = 0;
for (line) |c, i| {
map[(width * y) + x] = try std.fmt.parseInt(u8, line[i..i+1], 10);
x += 1;
}
y += 1;
}
// Determine local minima
var local_minima = std.AutoHashMap(Point, u8).init(alloc);
defer local_minima.deinit();
for (map) |v, i| {
var adjacents = get_adjacent_points(i, width, height);
//std.log.debug("Index {}: adjacents {any}", .{i, adjacents});
var is_minima = true;
for (adjacents) |adj| {
if (adj) |a| {
if (map[a] <= v) {
// std.log.debug(
// "Index {} (Point {},{}) not local minima due to index {} (Point {},{}): {} <= {}",
// .{i, i % width, i / height, a, a % width, a / height, map[a], v});
is_minima = false;
break;
}
}
}
if (is_minima) {
try local_minima.put(.{.x = i % width, .y = i / height}, v);
}
}
std.log.debug("Found {} local minima", .{local_minima.count()});
var mit = local_minima.iterator();
var danger_value: u16 = 0;
while (mit.next()) |kv| {
danger_value += kv.value_ptr.* + 1;
}
std.log.info("[Part 1] The risk level for all the low points on the map is {}",
.{danger_value});
var basin_sizes = std.ArrayList(usize).init(alloc);
defer basin_sizes.deinit();
mit = local_minima.iterator();
while (mit.next()) |kv| {
var point = kv.key_ptr.*;
var points_to_check = std.ArrayList(Point).init(alloc);
defer points_to_check.deinit();
try points_to_check.append(point);
var basin = std.AutoHashMap(Point, void).init(alloc);
defer basin.deinit();
try basin.put(point, undefined);
while (points_to_check.items.len > 0) {
point = points_to_check.pop();
var i = point.x + point .y * width;
var adjacents = get_adjacent_points(i, width, height);
for (adjacents) |adj| {
if (adj) |a| {
if (map[a] != 9) {
point = .{.x = a % width, .y = a / width};
if (basin.contains(point)) {
continue;
}
else {
try points_to_check.append(point);
try basin.put(point, undefined);
}
}
}
}
}
try basin_sizes.append(basin.count());
//std.log.debug("Basin for {}, {} is of size {}",
// .{kv.key_ptr.*.x, kv.key_ptr.*.y, basin.count()});
}
std.sort.sort(usize, basin_sizes.items, {}, comptime std.sort.desc(usize));
std.log.info("[Part 2] Product of 3 largest basins is: {}",
.{basin_sizes.items[0] * basin_sizes.items[1] * basin_sizes.items[2]});
}
fn get_adjacent_points(i: usize, width: usize, height: usize) [4]?usize {
var adjacents = [4] ?usize {
null,
null,
null,
null,
};
var ai: usize = 0;
if ((i % width) != 0) {
// left side
adjacents[ai] = i - 1;
ai += 1;
}
if (i >= width) {
// top side
adjacents[ai] = i - width;
ai += 1;
}
if ((i % width) != (width - 1)) {
// right side
adjacents[ai] = i + 1;
ai += 1;
}
if (i < ((height - 1) * width)) {
// bottom side
adjacents[ai] = i + width;
ai += 1;
}
return adjacents;
}
pub const Point = struct {
x: usize,
y: usize,
};