const std = @import("std"); const Io = std.Io; const shared = @import("shared.zig"); const print = shared.print; // limited single loop for part 1 pub fn findLargest(line: []const u8, charsLeft: usize) usize { var largest: u8 = 0; var index: usize = 0; for (line, 0..) |v, i| { if (v > largest and line.len - i > charsLeft) { // print("{d}", .{line[i] - '0'}); index = i; largest = line[i]; } } return index; } const RecursiveFind = struct { line: []const u8, arena: std.heap.ArenaAllocator, count: usize, backing: std.mem.Allocator, output: std.ArrayList(usize) = .empty, pub fn init(allocator: std.mem.Allocator, line: []const u8, count: usize) @This() { return .{ .line = line, .count = count, .backing = allocator, .arena = std.heap.ArenaAllocator.init(allocator), }; } pub fn deinit(self: *@This()) void { self.arena.deinit(); } pub fn toDigits(self: *@This(), allocator: std.mem.Allocator, out: *std.ArrayList(u8)) !void { for (self.output.items) |i| { try out.append(allocator, self.line[i]); } } // RecursiveFindNextLargestDigit pub fn rflnd(self: *@This(), offset: usize) void { const charsLeft = self.count - self.output.items.len; if (charsLeft == 0 or offset > self.line.len) return; const allocator = self.arena.allocator(); const subline = self.line[offset..self.line.len]; const index = findLargest(subline, charsLeft - 1) + offset; if (index == self.line.len) return; self.output.append(allocator, index) catch unreachable; rflnd(self, index + 1); } }; 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 part2: i64 = 0; var digits: std.ArrayList(u8) = .empty; defer digits.deinit(allocator); while (lineIter.next()) |l| { const line = shared.trim(l); var find = RecursiveFind.init(allocator, line, 2); find.rflnd(0); defer find.deinit(); digits.clearRetainingCapacity(); try find.toDigits(allocator, &digits); part1 += try std.fmt.parseInt(i64, digits.items, 10); var find2 = RecursiveFind.init(allocator, line, 12); defer find2.deinit(); find2.rflnd(0); digits.clearRetainingCapacity(); try find2.toDigits(allocator, &digits); part2 += try std.fmt.parseInt(i64, digits.items, 10); } print("part1 {d}", .{part1}); print("part2 {d}", .{part2}); }