const std = @import("std"); const Str = []const u8; const PATH = "input/day12.txt"; pub fn first(allocator: std.mem.Allocator) !isize { _ = allocator; return sumNumbers(@embedFile(PATH)); } pub fn second(allocator: std.mem.Allocator) !isize { const input = @embedFile(PATH); var sum = try sumNumbers(input); sum -= try ignoreObject(allocator, input); return sum; } test "day12a" { try std.testing.expectEqual(@as(isize, 156366), try first(std.testing.allocator)); } test "day12b" { try std.testing.expectEqual(@as(isize, 96852), try second(std.testing.allocator)); } fn sumNumbers(in: Str) !isize { var sum: isize = 0; var start_idx: usize = 0; var in_number: bool = false; var idx: usize = 0; while (idx < in.len) : (idx += 1) { switch (in[idx]) { '0'...'9' => { if (!in_number) { start_idx = idx; in_number = true; } }, else => { if (in_number) { if (in[start_idx - 1] == '-') { sum += try std.fmt.parseInt(isize, in[start_idx - 1 .. idx], 10); } else { sum += try std.fmt.parseUnsigned(isize, in[start_idx..idx], 10); } in_number = false; } }, } } return sum; } test "sumNumbers" { try std.testing.expectEqual(@as(isize, 6), try sumNumbers("[1,2,3]")); try std.testing.expectEqual(@as(isize, 6), try sumNumbers("{\"a\":2,\"b\":4}")); try std.testing.expectEqual(@as(isize, 3), try sumNumbers("{\"a\":{\"b\":4},\"c\":-1}")); try std.testing.expectEqual(@as(isize, 0), try sumNumbers("[-1,{\"a\":1}]")); } fn ignoreObject(allocator: std.mem.Allocator, in: Str) !isize { var ranges = std.ArrayList([2]usize).init(allocator); defer ranges.deinit(); var idx: usize = 0; red: while (idx < in.len) : (idx += 1) { if (in[idx] == 'r' and in[idx + 1] == 'e' and in[idx + 2] == 'd') { var curly_left: usize = 0; var bracket: usize = 0; var rstart: usize = idx - 1; // red while (rstart >= 0) : (rstart -= 1) { switch (in[rstart]) { // handle arrays (brackets) ']' => bracket += 1, '[' => { if (bracket == 0) break; bracket -= 1; }, // handle objects '{' => { if (curly_left == 0) { var curly_right: usize = 0; var rstop: usize = idx + 3; // red while (rstop < in.len) : (rstop += 1) { switch (in[rstop]) { '}' => { if (curly_right == 0) { // std.debug.print("{s}\n", .{in[rstart .. rstop + 1]}); // remove overlapping ranges var i: usize = ranges.items.len; while (i > 0) : (i -= 1) { if (ranges.items[i - 1][0] > rstart and ranges.items[i - 1][1] < rstop + 1) { // std.debug.print("remove: {}-{}\n", .{ ranges.items[i - 1][0], ranges.items[i - 1][1] }); _ = ranges.swapRemove(i - 1); } } try ranges.append(.{ rstart, rstop + 1 }); idx = rstop + 1; continue :red; } else curly_right -= 1; }, '{' => curly_right += 1, else => {}, } } } else curly_left -= 1; }, '}' => curly_left += 1, else => {}, } } } } var sum: isize = 0; for (ranges.items) |item| { sum += try sumNumbers(in[item[0]..item[1]]); } return sum; }