const std = @import("std"); const path = "data/day09/input.txt"; const RetType = u21; const directions = [4][2]i2{ .{ 1, 0 }, .{ 0, 1 }, .{ -1, 0 }, .{ 0, -1 }, }; const Point = struct { row: usize, col: usize, }; const grid_row = 100; const grid_col = 100; const GridType = u4; const GridArray = [grid_row][grid_col]GridType; const Grid = struct { array: GridArray, seen: std.AutoHashMap(Point, void), pub fn getBasin(self: *@This(), p: Point) anyerror!RetType { if (self.seen.contains(p)) { return 0; } try self.seen.put(p, {}); var ret: RetType = 1; for (directions) |dir| { const diffrow = @intCast(i10, p.row) + dir[0]; const diffcol = @intCast(i10, p.col) + dir[1]; if ((diffrow < 0) or (diffrow >= grid_row)) continue; if ((diffcol < 0) or (diffcol >= grid_col)) continue; if (self.array[@intCast(usize, diffrow)][@intCast(usize, diffcol)] != 9) { ret += try self.getBasin(Point{ .row = @intCast(usize, diffrow), .col = @intCast(usize, diffcol) }); } } return ret; } }; pub fn parseInput() anyerror!GridArray { const input = @embedFile(path); var lines = std.mem.split(u8, input, "\n"); var g: GridArray = undefined; var row: usize = 0; while (lines.next()) |line| : (row += 1) { for (line) |_, col| { g[row][col] = try std.fmt.parseUnsigned(GridType, line[col .. col + 1], 10); } } return g; } fn greaterThan(context: void, a: RetType, b: RetType) std.math.Order { _ = context; return std.math.order(a, b).invert(); } pub fn second(allocator: ?std.mem.Allocator) anyerror!RetType { var grid: Grid = .{ .array = try parseInput(), .seen = undefined, }; grid.seen = std.AutoHashMap(Point, void).init(allocator.?); defer grid.seen.deinit(); var basins = std.PriorityQueue(RetType, void, greaterThan).init(allocator.?, {}); defer basins.deinit(); for (grid.array) |line, row| { items: for (line) |item, col| { for (directions) |dir| { const diffrow = @intCast(i10, row) + dir[0]; const diffcol = @intCast(i10, col) + dir[1]; if ((diffrow < 0) or (diffrow >= grid_row)) continue; if ((diffcol < 0) or (diffcol >= grid_col)) continue; if (item >= grid.array[@intCast(usize, diffrow)][@intCast(usize, diffcol)]) { continue :items; } } const basin = try grid.getBasin(Point{ .row = row, .col = col }); try basins.add(basin); grid.seen.clearRetainingCapacity(); } } return basins.items[0] * basins.items[1] * basins.items[2]; } pub fn main() anyerror!void { var buf: [10_000]u8 = undefined; var fba = std.heap.FixedBufferAllocator.init(&buf); var timer = try std.time.Timer.start(); const ret = try second(fba.allocator()); const f = timer.lap() / 1000; try std.testing.expectEqual(ret, @as(RetType, 1100682)); std.debug.print("Day 9b result: {d} \t\ttime: {d}us\n", .{ ret, f }); } test "day09b" { try std.testing.expectEqual(@as(RetType, 1100682), try second(std.testing.allocator)); }