advent-of-code-2021/9/solve.zig

149 lines
3.6 KiB
Zig
Raw Normal View History

2021-12-09 10:10:24 +00:00
const std = @import("std");
pub fn main() !void {
var alloc = std.heap.GeneralPurposeAllocator(.{}){};
defer std.debug.assert(!alloc.deinit());
var gpa = &alloc.allocator;
const stdin = std.io.getStdIn().reader();
var riskLevels: u32 = 0;
var matrix = std.ArrayList([]u8).init(gpa);
defer matrix.deinit();
var tmp: [256]u8 = undefined;
while (try stdin.readUntilDelimiterOrEof(&tmp, '\n')) |line| {
var row = try gpa.alloc(u8, line.len);
for (line) |char, i| {
row[i] = char - 0x30;
}
try matrix.append(row);
}
var basins = std.ArrayList(u32).init(gpa);
defer basins.deinit();
for (matrix.items) |row, x| {
for (row) |tile, y| {
// check up
if (x != 0 and matrix.items[x-1][y] <= tile) {
continue;
}
// check down
if (x != (matrix.items.len - 1) and matrix.items[x+1][y] <= tile) {
continue;
}
// check left
if (y != 0 and row[y-1] <= tile) {
continue;
}
// check right
if (y != (row.len - 1) and row[y+1] <= tile) {
continue;
}
riskLevels += 1 + tile;
var walker = Walker().init(gpa, matrix);
defer walker.deinit();
var res = walker.start(@intCast(u32, x), @intCast(u32, y));
try basins.append(res);
}
}
std.debug.print("{}\n", .{riskLevels});
std.sort.sort(u32, basins.items, {}, comptime std.sort.desc(u32));
std.debug.print("{}\n", .{
basins.items[0] *
basins.items[1] *
basins.items[2]
});
// cleanup
for (matrix.items) |row| {
gpa.free(row);
}
}
fn Walker() type {
return struct {
const Self = @This();
matrix: std.ArrayList([]u8),
checked: std.ArrayList(u64),
result: u32 = 0,
fn init(alloc: *std.mem.Allocator, matrix: std.ArrayList([]u8)) Self {
return Self{
.matrix = matrix,
.checked = std.ArrayList(u64).init(alloc),
};
}
fn start(self: *Self, x: u32, y: u32) u32 {
// std.debug.print("starting from: {}, {}\n", .{x, y});
return self.check(x, y);
}
fn check(self: *Self, x: u32, y: u32) u32 {
var sum: u32 = 0;
var map = self.matrix.items;
var tile: u8 = map[x][y];
if (tile == 9) {
return 0;
}
var xy: u64 = x | @intCast(u64, y) << 32;
for (self.checked.items) |value| {
if (value == xy) {
return 0;
}
}
self.checked.append(xy) catch |err| {
return 0;
};
// count self
sum += 1;
// std.debug.print("tile: {}, {} = {}\n", .{x, y, tile});
// check up
if (x != 0 and map[x-1][y] > tile) {
sum += self.check(x-1, y);
}
// check down
if (x != (map.len - 1) and map[x+1][y] > tile) {
sum += self.check(x+1, y);
}
// check left
if (y != 0 and map[x][y-1] > tile) {
sum += self.check(x, y-1);
}
// check right
if (y != (map[0].len - 1) and map[x][y+1] > tile) {
sum += self.check(x, y+1);
}
return sum;
}
fn deinit(self: *Self) void {
self.checked.deinit();
}
};
}