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(); } }; }