diff --git a/src/days/day05.zig b/src/days/day05.zig index 38f67ca..9a3ebf6 100644 --- a/src/days/day05.zig +++ b/src/days/day05.zig @@ -3,44 +3,42 @@ 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 = @embedFile("./input/day05.txt"); + const input = + \\3-5 + \\10-14 + \\16-20 + \\12-18 + \\ + \\1 + \\5 + \\8 + \\11 + \\17 + \\32 + ; var lines = std.mem.tokenizeScalar(u8, input, '\n'); var ranges: std.ArrayList(Range) = .empty; defer ranges.deinit(allocator); - var accumulator: u32 = 0; + var accumulator: u64 = 0; - outer: while (lines.next()) |line| { + while (lines.next()) |line| { var components = std.mem.tokenizeScalar(u8, line, '-'); - const id_or_start_s = components.next() orelse continue; - const id_or_start = try std.fmt.parseUnsigned(u64, id_or_start_s, 10); - if (components.next()) |end_s| { - const end = try std.fmt.parseUnsigned(u64, end_s, 10); - try ranges.append(allocator, Range{ .start = id_or_start, .end = end }); - } else { - for (ranges.items) |range| { - if (id_or_start >= range.start and id_or_start <= range.end) { - accumulator += 1; - continue :outer; - } - } - } + 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), + }; + + const non_overlapping = try processRange(range, ranges.items, &accumulator, allocator); + accumulator += (non_overlapping.end + 1) - non_overlapping.start; + + try ranges.append(allocator, range); } var buffer: [64]u8 = undefined; @@ -52,8 +50,94 @@ pub fn run(allocator: std.mem.Allocator) !void { try stdout.flush(); } +fn processRange( + range: Range, + ranges: []Range, + accumulator: *u64, + allocator: std.mem.Allocator, +) !Range { + std.debug.print("considering {f}\n", .{range}); + + var overlapped = false; + for (ranges) |other| { + const overlaps = try range.overlaps(allocator, &other); + if (overlaps) |outside| { + defer allocator.free(outside); + + std.debug.assert(outside.len <= 2); + + overlapped = true; + + std.debug.print("- overlaps with {f}\n", .{other}); + + if (outside.len == 0) { + std.debug.print("- overlap is exactly equal\n", .{}); + return range; + } + + var previous_non_overlapping: ?Range = null; + for (outside, 0..) |r, i| { + std.debug.print("\t+ ({d}) {f} falls outside\n", .{i, r}); + + const non_overlapping = try processRange(r, ranges, accumulator, allocator); + if ((i + 1) == outside.len) { + return non_overlapping; + } + if (previous_non_overlapping) |p| { + std.debug.print("+ comparing ({f}) to ({f})\n", .{non_overlapping, p}); + if (!non_overlapping.eql(&p)) { + return non_overlapping; + } + } + previous_non_overlapping = non_overlapping; + } + } + } + + if (!overlapped) { + std.debug.print("- no overlap with other range\n", .{}); + return range; + } + + unreachable; +} + const Range = struct { start: u64, end: u64, + + const Self = @This(); + + 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: *const Self, other: *const Self) bool { + return self.start == other.start and self.end == other.end; + } + + pub fn overlaps(self: *const Self, allocator: std.mem.Allocator, other: *const Self) !?[]Self { + if (self.start <= other.end and self.end >= other.start) { + var l: std.ArrayList(Self) = try .initCapacity(allocator, 2); + defer l.deinit(allocator); + + if (self.start < other.start) { + try l.append(allocator, Range{ .start = self.start, .end = other.start - 1 }); + } + if (self.end > other.end) { + try l.append(allocator, Range{ .start = other.end + 1, .end = self.end }); + } + if (other.start < self.start) { + try l.append(allocator, Range{ .start = other.start, .end = self.start - 1 }); + } + if (other.end > self.end) { + try l.append(allocator, Range{ .start = self.end + 1, .end = other.end }); + } + + return try l.toOwnedSlice(allocator); + } else { + return null; + } + } };