148 lines
3.6 KiB
Zig
148 lines
3.6 KiB
Zig
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();
|
|
}
|
|
};
|
|
}
|