You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
235 lines
7.0 KiB
235 lines
7.0 KiB
1 year ago
|
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()});
|
||
|
}
|