176 lines
4.6 KiB
Zig
176 lines
4.6 KiB
Zig
const std = @import("std");
|
|
const alloc = std.heap.page_allocator;
|
|
const List = std.ArrayList;
|
|
pub const Mappings = std.AutoHashMap(MappingKey, Mapping);
|
|
pub const Idx = u64;
|
|
|
|
pub const SeedList = List(Idx);
|
|
|
|
pub const MappingType = enum {
|
|
Seed,
|
|
Soil,
|
|
Fertilizer,
|
|
Water,
|
|
Light,
|
|
Temperature,
|
|
Humidity,
|
|
Location,
|
|
};
|
|
|
|
pub const MappingKey = struct {
|
|
MappingType,
|
|
MappingType,
|
|
};
|
|
|
|
pub const Mapping = struct {
|
|
dest_ranges: []MappingRange,
|
|
source_ranges: []MappingRange,
|
|
|
|
pub fn get(self: Mapping, val: Idx) Idx {
|
|
for (self.source_ranges, 0..) |src_range, i| {
|
|
if (val >= src_range.start and val < src_range.end) {
|
|
const dest_range = self.dest_ranges[i];
|
|
const dest_offset = (val - src_range.start);
|
|
return dest_range.start + dest_offset;
|
|
}
|
|
}
|
|
|
|
return val;
|
|
}
|
|
};
|
|
|
|
pub const Input = struct {
|
|
mappings: Mappings,
|
|
seeds: SeedList,
|
|
};
|
|
|
|
pub const MappingRange = struct {
|
|
start: Idx,
|
|
end: Idx,
|
|
};
|
|
|
|
pub fn parse(data: []const u8) !Input {
|
|
var lines = std.mem.tokenizeSequence(u8, data, "\n");
|
|
|
|
var mappings = Mappings.init(alloc);
|
|
var seeds: SeedList = undefined;
|
|
var mapping_types: [2]MappingType = undefined;
|
|
var dest_ranges = List(MappingRange).init(alloc);
|
|
var source_ranges = List(MappingRange).init(alloc);
|
|
var collect_mapping = false;
|
|
|
|
while (lines.next()) |line| {
|
|
if (std.mem.startsWith(u8, line, "seeds:")) {
|
|
seeds = try parse_seed_list(line);
|
|
} else if (std.mem.endsWith(u8, line, "map:")) {
|
|
mapping_types = parse_mapping_header(line);
|
|
} else {
|
|
const range = try parse_mapping_body(line);
|
|
try dest_ranges.append(range[0]);
|
|
try source_ranges.append(range[1]);
|
|
}
|
|
|
|
if (lines.peek()) |next_line| {
|
|
const new_mapping = std.mem.endsWith(u8, next_line, "map:");
|
|
collect_mapping = new_mapping and dest_ranges.items.len != 0;
|
|
} else {
|
|
collect_mapping = true;
|
|
}
|
|
|
|
if (collect_mapping) {
|
|
const dranges = try dest_ranges.toOwnedSlice();
|
|
const sranges = try source_ranges.toOwnedSlice();
|
|
|
|
const mapping = .{
|
|
.dest_ranges = dranges,
|
|
.source_ranges = sranges,
|
|
};
|
|
|
|
const key = .{
|
|
mapping_types[0],
|
|
mapping_types[1],
|
|
};
|
|
|
|
try mappings.put(key, mapping);
|
|
}
|
|
}
|
|
|
|
const parsed = .{ .mappings = mappings, .seeds = seeds };
|
|
|
|
return parsed;
|
|
}
|
|
|
|
fn parse_seed_list(line: []const u8) !SeedList {
|
|
var list = SeedList.init(alloc);
|
|
|
|
var seeds = std.mem.tokenizeSequence(u8, line, " ");
|
|
_ = seeds.next();
|
|
|
|
while (seeds.next()) |seed| {
|
|
const seed_num = try std.fmt.parseInt(Idx, seed, 10);
|
|
try list.append(seed_num);
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
fn parse_mapping_header(line: []const u8) [2]MappingType {
|
|
const map_types = std.mem.trimRight(u8, line, " map:");
|
|
|
|
var map_types_iter = std.mem.tokenizeSequence(u8, map_types, "-to-");
|
|
|
|
var types: [2]MappingType = undefined;
|
|
|
|
var i: u8 = 0;
|
|
while (map_types_iter.next()) |map_type| {
|
|
if (std.mem.eql(u8, map_type, "seed")) {
|
|
types[i] = MappingType.Seed;
|
|
} else if (std.mem.eql(u8, map_type, "soil")) {
|
|
types[i] = MappingType.Soil;
|
|
} else if (std.mem.eql(u8, map_type, "fertilizer")) {
|
|
types[i] = MappingType.Fertilizer;
|
|
} else if (std.mem.eql(u8, map_type, "water")) {
|
|
types[i] = MappingType.Water;
|
|
} else if (std.mem.eql(u8, map_type, "light")) {
|
|
types[i] = MappingType.Light;
|
|
} else if (std.mem.eql(u8, map_type, "temperature")) {
|
|
types[i] = MappingType.Temperature;
|
|
} else if (std.mem.eql(u8, map_type, "humidity")) {
|
|
types[i] = MappingType.Humidity;
|
|
} else if (std.mem.eql(u8, map_type, "location")) {
|
|
types[i] = MappingType.Location;
|
|
} else {
|
|
unreachable;
|
|
}
|
|
|
|
i += 1;
|
|
}
|
|
|
|
return types;
|
|
}
|
|
|
|
fn parse_mapping_body(line: []const u8) ![2]MappingRange {
|
|
var values = std.mem.tokenizeScalar(u8, line, ' ');
|
|
|
|
var parsed: [3]Idx = undefined;
|
|
|
|
var i: u8 = 0;
|
|
while (values.next()) |val| {
|
|
const num = try std.fmt.parseInt(Idx, val, 10);
|
|
parsed[i] = num;
|
|
i += 1;
|
|
}
|
|
|
|
const dest_range = .{
|
|
.start = parsed[0],
|
|
.end = parsed[0] + parsed[2],
|
|
};
|
|
|
|
const source_range = .{
|
|
.start = parsed[1],
|
|
.end = parsed[1] + parsed[2],
|
|
};
|
|
|
|
return .{ dest_range, source_range };
|
|
}
|