const std = @import("std"); const Io = std.Io; const shared = @import("shared.zig"); const print = shared.print; pub fn insertIfNotSmallest(allocator: std.mem.Allocator, list: *std.ArrayList(Result), value: u8, index: usize) !void { for (list.items) |result| { if (value > result.value) { try list.append(allocator, .{ .index = index, .value = value }); break; } } std.mem.sort(Result, list.items, {}, Result.compareValues); } const Result = struct { index: usize, value: u8, pub fn compareValues(_: void, lhs: @This(), rhs: @This()) bool { return lhs.value > rhs.value; } pub fn compareIndex(_: void, lhs: @This(), rhs: @This()) bool { return lhs.index < rhs.index; } }; pub fn selectNLargest(comptime N: usize, allocator: std.mem.Allocator, line: []const u8) ![N]usize { var list: std.ArrayList(Result) = .empty; try list.appendNTimes(allocator, .{ .index = line.len, .value = 0 }, N); defer list.deinit(allocator); for (line, 0..) |x, i| { try insertIfNotSmallest(allocator, &list, x, i); while (list.items.len > 2) { _ = list.pop(); } } std.mem.sort(Result, list.items, {}, Result.compareIndex); var rv: [N]usize = .{ line.len, line.len }; for (0..N) |i| { rv[i] = list.items[i].index; } return rv; } pub fn main(init: std.process.Init) !void { try shared.sharedInit(init); const allocator: std.mem.Allocator = init.arena.allocator(); const bytes = shared.loadBytesArg(allocator); var lineIter = std.mem.tokenizeScalar(u8, bytes, '\n'); var part1: i64 = 0; var digits: std.ArrayList(u8) = .empty; defer digits.deinit(allocator); while (lineIter.next()) |l| { const line = shared.trim(l); const x = try selectNLargest(2, allocator, line); digits.clearRetainingCapacity(); for (0..x.len) |i| { try digits.append(allocator, line[x[i]]); } print("{s}", .{digits.items}); part1 += try std.fmt.parseInt(i64, digits.items, 10); } print("part1 {d}", .{part1}); }