const std = @import("std"); test { std.debug.assert(try part1( \\3 4 \\4 3 \\2 5 \\1 3 \\3 9 \\3 3 ) == 11); } const Input = struct { lefts: std.ArrayList(u32), rights: std.ArrayList(u32), }; pub fn parse(allocator: std.mem.Allocator, input: []const u8) !Input { var lines = std.mem.split(u8, input, "\n"); var lefts = std.ArrayList(u32).init(allocator); // defer lefts.deinit(); var rights = std.ArrayList(u32).init(allocator); // defer rights.deinit(); while (lines.next()) |line| { if (line.len == 0) continue; var words = std.mem.split(u8, line, " "); const left = try std.fmt.parseInt(u32, words.next() orelse return error.InvalidInput, 10); const right = try std.fmt.parseInt(u32, words.next() orelse return error.InvalidInput, 10); try lefts.append(left); try rights.append(right); } return .{ .lefts = lefts, .rights = rights }; } pub fn part1(_: std.mem.Allocator, input: Input) !u32 { std.mem.sort(u32, input.lefts.items, {}, std.sort.asc(u32)); std.mem.sort(u32, input.rights.items, {}, std.sort.asc(u32)); var sum: u32 = 0; for (input.lefts.items, input.rights.items) |l, r| { sum += @max(l, r) - @min(l, r); } return sum; } pub fn part2(allocator: std.mem.Allocator, input: Input) !u32 { var right_counts = std.AutoHashMap(u32, u16).init(allocator); defer right_counts.deinit(); for (input.rights.items) |right| { const entry = try right_counts.getOrPut(right); if (entry.found_existing) entry.value_ptr.* += 1 else entry.value_ptr.* = 1; } var sum: u32 = 0; for (input.lefts.items) |x| { const count: u32 = @intCast(right_counts.get(x) orelse 0); sum += x * count; } return sum; }