const std = @import("std"); fn StackList(comptime T: type, comptime capacity_type: type, comptime capacity: capacity_type) type { return struct { const Self = @This(); mem: [capacity]T, length: capacity_type, fn add(self: *Self, value: T) void { self.mem[self.length] = value; self.length += 1; } fn has(self: *const Self, needle: T) bool { for (0..self.length) |i| { if (self.mem[i] == needle) { return true; } } return false; } fn getSlice(self: *Self) []T { //var mem_full_slice = &self.mem; //var mem_slice: []T = mem_full_slice[0..self.length]; //return mem_slice; return (&self.mem)[0..self.length]; } fn reset(self: *Self) void { self.length = 0; } fn init() Self { return Self{ .mem = undefined, .length = 0, }; } }; } const Range = struct { start: u64, end: u64, fn clear(self: *Range) void { self.start = std.math.maxInt(u64); self.end = std.math.maxInt(u64); } }; const StateStorage = StackList(Range, u32, 10_000); const State = struct { a: StateStorage = StateStorage.init(), b: StateStorage = StateStorage.init(), is_a_current: bool = true, fn getCurrent(self: *State) *StateStorage { return switch (self.is_a_current) { true => &self.a, false => &self.b, }; } fn getPrevious(self: *State) *StateStorage { return switch (self.is_a_current) { true => &self.b, false => &self.a, }; } fn add(self: *State, value: Range) void { self.getCurrent().*.add(value); } fn addMapping(self: *State, destination_start: u64, source_start: u64, range_length: u64) void { const source_end = source_start + range_length; //std.debug.print("processing mapping from {d}-{d} (length {d}) to {d}\n", .{ source_start, source_end, range_length, destination_start }); for (self.getPrevious().*.getSlice()) |*range_ptr| { const range = range_ptr.*; //std.debug.print("processing range {d}-{d}\n", .{ range.start, range.end }); if (source_start <= range.start) { if (source_end <= range.start) { // no intersection } else if (source_end < range.end) { self.add(Range{ .start = destination_start + (range.start - source_start), .end = destination_start + (source_end - source_start), }); range_ptr.*.start = source_end; } else { self.add(Range{ .start = destination_start + (range.start - source_start), .end = destination_start + (range.end - source_start), }); range_ptr.*.clear(); } } else if (source_start < range.end) { if (source_end < range.end) { self.add(Range{ .start = destination_start, .end = destination_start + (source_end - source_start), }); range_ptr.*.end = source_start; self.getPrevious().*.add(Range{ .start = source_end, .end = range.end, }); } else { self.add(Range{ .start = destination_start, .end = destination_start + (range.end - source_start), }); range_ptr.*.end = source_start; } } } } fn finishMappings(self: *State) void { //std.debug.print("previous values: {any}\n", .{self.getPrevious().*.getSlice()}); for (self.getPrevious().*.getSlice()) |range| { if (range.start < range.end) { self.add(range); } } self.is_a_current = !self.is_a_current; self.getCurrent().*.reset(); } fn getMinPreviousValue(self: *State) u64 { var previous = self.getPrevious().*; var result: u32 = std.math.maxInt(u32); for (previous.getSlice()) |range| { result = @min(result, range.start); } return result; } fn debug(self: *State) void { _ = self; //std.debug.print("Current state: {any}, previous state: {any}\n", .{ self.getCurrent().*.getSlice(), self.getPrevious().*.getSlice() }); } }; fn addDigit(result: anytype, digit: u8) void { result.* = (result.* * 10) + (digit - '0'); } fn parseFirstLine(line: []const u8) State { var result = State{}; var index: usize = 7; while (index < line.len) { var range_start: u64 = 0; var range_length: u64 = 0; while (line[index] != ' ') : (index += 1) { addDigit(&range_start, line[index]); } index += 1; while (index < line.len and line[index] != ' ') : (index += 1) { addDigit(&range_length, line[index]); } result.add(Range{ .start = range_start, .end = range_start + range_length, }); index += 1; } return result; } fn parseMappingLine(line: []const u8, state: *State) void { var destination_start: u64 = 0; var source_start: u64 = 0; var range_length: u64 = 0; var index: usize = 0; while (line[index] != ' ') : (index += 1) { addDigit(&destination_start, line[index]); } index += 1; while (line[index] != ' ') : (index += 1) { addDigit(&source_start, line[index]); } index += 1; while (index < line.len) : (index += 1) { addDigit(&range_length, line[index]); } state.addMapping(destination_start, source_start, range_length); } pub fn main() !void { const stdout = std.io.getStdOut().writer(); const raw_in = std.io.getStdIn(); var buffered_reader = std.io.bufferedReader(raw_in.reader()); var reader = buffered_reader.reader(); var line_buffer: [1000]u8 = undefined; const first_line = (try reader.readUntilDelimiterOrEof(&line_buffer, '\n')).?; var state = parseFirstLine(first_line); state.debug(); _ = try reader.readUntilDelimiterOrEof(&line_buffer, '\n'); _ = try reader.readUntilDelimiterOrEof(&line_buffer, '\n'); state.finishMappings(); state.debug(); while (try reader.readUntilDelimiterOrEof(&line_buffer, '\n')) |line| { if (line.len != 0) { parseMappingLine(line, &state); } else { _ = try reader.readUntilDelimiterOrEof(&line_buffer, '\n'); state.finishMappings(); state.debug(); } } state.finishMappings(); state.debug(); try stdout.print("{d}\n", .{state.getMinPreviousValue()}); }