const std = @import("std"); pub fn main() void { const input = @embedFile("input"); var part1: usize = 0; // Go through each command one by one var iter = dirIterator.init(input); const root = sumSizes(&iter, 100_000, &part1); std.debug.print("Part 1: {}\n", .{part1}); var part2: usize = 0; _ = findBiggest(iter.reset(), root - 40_000_000, &part2); std.debug.print("Part 2: {}\n", .{part2}); } fn eql(a: []const u8, b: []const u8) bool { return std.mem.eql(u8, a, b); } fn findBiggest(iter: *dirIterator, minimum: usize, global: *usize) usize { var size: usize = 0; while (iter.next()) |cmd| { size += switch (cmd) { .file => iter.parseSize(), .dirEnter => findBiggest(iter, minimum, global), .dirExit => break, }; } // If the size doesn't exceed the limit, add it to the total if (size > minimum and (size < global.* or global.* == 0)) global.* = size; // Return the size witout filtering return size; } fn sumSizes(iter: *dirIterator, limit: usize, total: *usize) usize { var size: usize = 0; while (iter.next()) |cmd| { size += switch (cmd) { .file => iter.parseSize(), .dirEnter => sumSizes(iter, limit, total), .dirExit => break, }; } // If the size doesn't exceed the limit, add it to the total total.* += if (size <= limit) size else 0; // Return the size witout filtering return size; } // Helper to iterate through the commands const dirIterator = struct { iter: std.mem.SplitIterator(u8), const cmdType = enum { dirEnter, dirExit, file, }; pub fn init(input: []const u8) dirIterator { return .{ .iter = std.mem.split(u8, input, "\n") }; } // Returns the file size of the current line or 0 pub fn parseSize(self: dirIterator) usize { const numSlice = std.mem.sliceTo(self.iter.rest(), ' '); return std.fmt.parseInt(usize, numSlice, 10) catch 0; } pub fn next(self: *dirIterator) ?cmdType { // Go through each command one by one while (self.iter.next()) |line| { // Not a valid input if (line.len <= 0) continue; // Changing folder (quitting or recursing) if (line.len > 5 and eql(line[0..5], "$ cd ")) { // Reached the end of the folder if (eql(line[5..], "..")) return cmdType.dirExit; // "cd" command not to parent, then it's a child return cmdType.dirEnter; } // Not a cd, maybe it's a size return cmdType.file; } // Exhausted the input return null; } pub fn reset(self: *dirIterator) *dirIterator { self.iter.reset(); return self; } };