const std = @import("std"); const Op = enum(u64) { add = 0, mult = 1, }; fn readItem(reader: *std.io.Reader) !struct { []u8, bool } { var s = try reader.peekDelimiterExclusive(' '); if (std.mem.indexOfScalar(u8, s, '\n')) |len| { reader.toss(len + 1); return .{ s[0..len], true }; } else { reader.toss(s.len + 1); return .{ s, false }; } } fn reduce(values: []u64, start: usize, skip: usize, op: Op) u64 { var i: usize = start; var result: u64 = @intFromEnum(op); while (i < values.len) { result = switch (op) { Op.add => result + values[i], Op.mult => result * values[i], }; i += skip; } return result; } fn reduceColumns( gpa: std.mem.Allocator, columns: *std.array_list.Aligned(u64, null), values: []u64, offsets: []usize, start: usize, skip: usize, op: Op, ) !u64 { std.debug.assert(values.len == offsets.len); var i: usize = start; var maxOffset: usize = offsets[i]; defer columns.clearRetainingCapacity(); while (i < values.len) { while (maxOffset < offsets[i]) { try columns.insert(gpa, 0, 0); maxOffset += 1; } var j = maxOffset - offsets[i]; var value = values[i]; while (value != 0) { if (j < columns.items.len) { columns.items[j] *= 10; columns.items[j] += value % 10; } else { try columns.append(gpa, value % 10); } value /= 10; j += 1; } i += skip; } return reduce(columns.items, 0, 1, op); } pub fn main() !void { const gpa = std.heap.smp_allocator; const path: [:0]const u8 = std.mem.span(std.os.argv[1]); var file = try std.fs.cwd().openFile(path, .{}); defer file.close(); var buffer: [1024]u8 = undefined; var reader = file.reader(&buffer); var i: usize = 0; var offset: usize = 0; var width: usize = 0; var values = std.ArrayList(u64).empty; defer values.deinit(gpa); var offsets = std.ArrayList(usize).empty; defer offsets.deinit(gpa); var columns = std.ArrayList(u64).empty; defer columns.deinit(gpa); var part1: u64 = 0; var part2: u64 = 0; while (readItem(&reader.interface)) |item| { const s, const lineEnd = item; offset += s.len + 1; if (s.len != 0) { if (s[0] == '+') { part1 += reduce(values.items, i, width, Op.add); part2 += try reduceColumns(gpa, &columns, values.items, offsets.items, i, width, Op.add); } else if (s[0] == '*') { part1 += reduce(values.items, i, width, Op.mult); part2 += try reduceColumns(gpa, &columns, values.items, offsets.items, i, width, Op.mult); } else { const value = try std.fmt.parseInt(u64, s, 10); try values.append(gpa, value); try offsets.append(gpa, offset); } i += 1; } if (lineEnd) { width = i; i = 0; offset = 0; } } else |err| switch (err) { error.EndOfStream => {}, else => |e| return e, } std.debug.print("part1: {}\n", .{part1}); std.debug.print("part2: {}\n", .{part2}); }