const std = @import("std"); pub const title = "Day 05: Cafeteria"; pub fn run(allocator: std.mem.Allocator) !void { const input = @embedFile("./input/day05.txt"); //const input = // \\3-5 // \\10-14 // \\16-20 // \\12-18 // \\ // \\1 // \\5 // \\8 // \\11 // \\17 // \\32 // ; //const input = // \\383043617664892-389277822354893 // \\387921155483286-389277822354893 // ; var lines = std.mem.tokenizeScalar(u8, input, '\n'); var ranges: std.ArrayList(Range) = .empty; defer ranges.deinit(allocator); var accumulator: u64 = 0; var i: usize = 0; while (lines.next()) |line| { var components = std.mem.tokenizeScalar(u8, line, '-'); const start_s = components.next() orelse continue; const end_s = components.next() orelse break; const range = Range{ .start = try std.fmt.parseUnsigned(u64, start_s, 10), .end = try std.fmt.parseUnsigned(u64, end_s, 10), }; std.debug.print("==> range {d}\n", .{i}); processRange(range, ranges.items, &accumulator, 0); try ranges.append(allocator, range); i += 1; } var buffer: [64]u8 = undefined; var stdout_writer = std.fs.File.stdout().writer(&buffer); const stdout = &stdout_writer.interface; try stdout.print("{d}\n", .{accumulator}); try stdout.flush(); } fn processRange( range: Range, ranges: []Range, accumulator: *u64, level: usize, ) void { for (0..level) |_| std.debug.print("\t", .{}); std.debug.print("recursion level = {d}\n", .{level}); for (0..level) |_| std.debug.print("\t", .{}); std.debug.print("considering {f}\n", .{range}); var overlapped = false; for (ranges) |other| { const difference = range.symmetricDifference(other); if (difference.overlapping) { overlapped = true; if (range.eql(other)) { return; } for (0..level) |_| std.debug.print("\t", .{}); std.debug.print("- overlaps with {f}\n", .{other}); if (difference.left != null and difference.right != null) { const left = difference.left.?; const right = difference.right.?; for (0..level) |_| std.debug.print("\t", .{}); std.debug.print("- left = {f}, right = {f}\n", .{left, right}); if (left.eql(right)) { return; } if (left.start == range.start) { processRange(left, ranges, accumulator, level + 1); } if (right.end == range.end) { processRange(right, ranges, accumulator, level + 1); } } else if (difference.left) |left| { for (0..level) |_| std.debug.print("\t", .{}); std.debug.print("- left = {f}\n", .{left}); if (left.start == range.start) { processRange(left, ranges, accumulator, level + 1); } } else if (difference.right) |right| { for (0..level) |_| std.debug.print("\t", .{}); std.debug.print("- right = {f}\n", .{right}); if (right.end == range.end) { processRange(right, ranges, accumulator, level + 1); } } return; } } if (!overlapped) { const n = (range.end + 1) - range.start; std.debug.print("- no overlap with other range, adding {d}\n", .{n}); accumulator.* += n; } } const Range = struct { start: u64, end: u64, const Self = @This(); pub const SymmetricDifference = struct { left: ?Self = null, right: ?Self = null, overlapping: bool, }; pub fn format(self: Range, w: *std.io.Writer) std.io.Writer.Error!void { try w.print("{d} to {d}", .{self.start, self.end}); } pub fn eql(self: Self, other: Self) bool { return self.start == other.start and self.end == other.end; } pub fn symmetricDifference(self: Self, other: Self) SymmetricDifference { const overlapping = self.start <= other.end and self.end >= other.start; if (!overlapping) { const left, const right = if (self.end < other.start) .{ self, other } else .{ other, self }; return .{ .left = left, .right = right, .overlapping = overlapping, }; } var difference: SymmetricDifference = .{ .overlapping = overlapping }; if (self.start < other.start) { difference.left = .{ .start = self.start, .end = other.start - 1, }; } else if (other.start < self.start) { difference.left = .{ .start = other.start, .end = self.start - 1, }; } if (self.end > other.end) { difference.right = .{ .start = other.end + 1, .end = self.end, }; } else if (other.end > self.end) { difference.right = .{ .start = self.end + 1, .end = other.end, }; } return difference; } };