hey lmao day05
This commit is contained in:
parent
faf81869d6
commit
0f2044b762
248
src/day05.zig
248
src/day05.zig
@ -5,117 +5,179 @@ const mem = std.mem;
|
||||
pub fn main() !void {
|
||||
const input = @embedFile("data/day05.txt");
|
||||
const sln = try solve(util.gpa, input);
|
||||
std.debug.print("{d}\n", .{sln.a});
|
||||
std.debug.print("{d}\n", .{sln.b});
|
||||
std.debug.print("{d}\n", .{sln});
|
||||
std.debug.print("{d}\n", .{sln});
|
||||
}
|
||||
|
||||
const Solution = struct {
|
||||
a: usize,
|
||||
b: usize,
|
||||
};
|
||||
fn Range(comptime T: type) type {
|
||||
return struct {
|
||||
start: T,
|
||||
end: T,
|
||||
|
||||
const Transform = struct {
|
||||
from: []const u8,
|
||||
to: []const u8,
|
||||
};
|
||||
const Self = @This();
|
||||
|
||||
/// Returns the intersection of two ranges.
|
||||
pub fn intersect(self: Self, other: Self) ?Self {
|
||||
const a = if (self.start < other.start) self else other;
|
||||
const b = if (self.start < other.start) other else self;
|
||||
// std.debug.print("{any}/{any}\n", .{ a, b });
|
||||
|
||||
if (a.start == a.end or b.start == b.end) return null; // Points don't intersect.
|
||||
|
||||
if (a.end < b.start) return null; // No intersection.
|
||||
if (a.end > b.end) return b; // A is a superset of B.
|
||||
return .{ .start = b.start, .end = a.end };
|
||||
}
|
||||
|
||||
/// Returns the union of two ranges.
|
||||
pub fn join(self: Self, other: Self) ?Self {
|
||||
if (self.intersect(other) == null) return null; // Can't union disjoint ranges.
|
||||
// std.debug.print("merge {any}+{any}\n", .{ self, other });
|
||||
// Now guaranteed that they overlap.
|
||||
const merged = Self{ .start = @min(self.start, other.start), .end = @max(self.end, other.end) };
|
||||
std.debug.print("= {any}\n", .{merged});
|
||||
return merged;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
test "range intersect" {
|
||||
const R = Range(usize);
|
||||
const e = .{ .start = 2, .end = 5 };
|
||||
// Superset
|
||||
try std.testing.expectEqual(e, (R{ .start = 0, .end = 6 }).intersect(.{ .start = 2, .end = 5 }));
|
||||
try std.testing.expectEqual(e, (R{ .start = 2, .end = 5 }).intersect(.{ .start = 0, .end = 6 }));
|
||||
// A < B
|
||||
try std.testing.expectEqual(e, (R{ .start = 0, .end = 5 }).intersect(.{ .start = 2, .end = 6 }));
|
||||
// B < A
|
||||
try std.testing.expectEqual(e, (R{ .start = 2, .end = 6 }).intersect(.{ .start = 0, .end = 5 }));
|
||||
// No intersect
|
||||
try std.testing.expect(null == (R{ .start = 0, .end = 3 }).intersect(.{ .start = 4, .end = 6 }));
|
||||
}
|
||||
|
||||
const Map = struct {
|
||||
dest_start: usize,
|
||||
source_start: usize,
|
||||
range: usize,
|
||||
offset: isize,
|
||||
source: Range(usize),
|
||||
};
|
||||
|
||||
const Component = struct {
|
||||
name: []const u8,
|
||||
value: usize,
|
||||
stage: usize,
|
||||
range: Range(usize),
|
||||
};
|
||||
|
||||
const UsizeSet = std.AutoHashMap(usize, void);
|
||||
fn mergeRanges(ranges: *std.ArrayList(Component)) void {
|
||||
var i: usize = 0;
|
||||
while (i < ranges.items.len) : (i += 1) {
|
||||
var item = ranges.items[i];
|
||||
var j = i + 1;
|
||||
while (j < ranges.items.len) {
|
||||
const next = ranges.items[j];
|
||||
if (item.range.join(next.range)) |merged| {
|
||||
const merged_item = .{ .stage = item.stage, .range = merged };
|
||||
item = merged_item;
|
||||
ranges.items[i] = merged_item;
|
||||
_ = ranges.swapRemove(j);
|
||||
} else {
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn solve(alloc: mem.Allocator, input: []const u8) !Solution {
|
||||
test "mergeRanges" {
|
||||
var ranges = std.ArrayList(Component).init(std.testing.allocator);
|
||||
defer ranges.deinit();
|
||||
try ranges.append(.{ .stage = 0, .range = .{ .start = 79, .end = 93 } });
|
||||
try ranges.append(.{ .stage = 0, .range = .{ .start = 55, .end = 66 } });
|
||||
try ranges.append(.{ .stage = 0, .range = .{ .start = 70, .end = 10 } });
|
||||
mergeRanges(&ranges);
|
||||
try std.testing.expectEqual(.{ .start = 70, .end = 93 }, ranges.items[0].range);
|
||||
try std.testing.expectEqual(.{ .start = 55, .end = 66 }, ranges.items[1].range);
|
||||
}
|
||||
|
||||
fn solve(alloc: mem.Allocator, input: []const u8) !usize {
|
||||
var it = util.splitLines(input);
|
||||
const seed_line = it.next().?;
|
||||
const seeds = try util.parseIntsScalar(usize, alloc, seed_line[mem.indexOfScalar(u8, seed_line, ':').? + 1 ..], .{});
|
||||
defer alloc.free(seeds);
|
||||
|
||||
var last_values = UsizeSet.init(alloc);
|
||||
var working_values = UsizeSet.init(alloc);
|
||||
defer last_values.deinit();
|
||||
defer working_values.deinit();
|
||||
var ranges = std.ArrayList(Component).init(alloc);
|
||||
defer ranges.deinit();
|
||||
var lowest_location: usize = std.math.maxInt(usize);
|
||||
|
||||
var low_loc: usize = std.math.maxInt(usize);
|
||||
|
||||
var seeds_index: usize = 0;
|
||||
while (seeds_index < seeds.len) : (seeds_index += 2) {
|
||||
last_values.clearRetainingCapacity();
|
||||
working_values.clearRetainingCapacity();
|
||||
|
||||
std.debug.print("= seeding {d}/{d} =\n", .{ seeds_index, seeds.len });
|
||||
const start = seeds[seeds_index];
|
||||
const range = seeds[seeds_index + 1];
|
||||
for (start..start + range) |seed| {
|
||||
// std.debug.print("seed {d}\n", .{seed});
|
||||
try working_values.put(seed, {});
|
||||
}
|
||||
|
||||
// Reset parse input.
|
||||
it = util.splitLines(input);
|
||||
_ = it.next().?;
|
||||
var current_component: []const u8 = undefined;
|
||||
while (it.next()) |line| {
|
||||
if (line.len == 0) {
|
||||
std.debug.print("== swap ==\n", .{});
|
||||
// Copy all remaining
|
||||
var lv_it = last_values.iterator();
|
||||
while (lv_it.next()) |entry| {
|
||||
try working_values.put(entry.key_ptr.*, {});
|
||||
}
|
||||
// Swap working sets
|
||||
mem.swap(UsizeSet, &last_values, &working_values);
|
||||
working_values.clearRetainingCapacity();
|
||||
} else if (mem.endsWith(u8, line, "map:")) {
|
||||
var t_it = util.split(line, ' ');
|
||||
var comp_it = util.split(t_it.next().?, '-');
|
||||
_ = comp_it.next(); // A
|
||||
_ = comp_it.next(); // to
|
||||
current_component = comp_it.next().?; // B
|
||||
} else {
|
||||
std.debug.print("== {s} {d}/{d}\n", .{ current_component, working_values.count(), last_values.count() });
|
||||
const map = try util.parseIntsScalar(usize, alloc, line, .{});
|
||||
defer alloc.free(map);
|
||||
|
||||
var to_delete = UsizeSet.init(alloc);
|
||||
defer to_delete.deinit();
|
||||
var lv_it = last_values.iterator();
|
||||
while (lv_it.next()) |entry| {
|
||||
// if (transitioned[index]) {
|
||||
// std.debug.print("{d} already mapped\n", .{index});
|
||||
// continue :map_blk;
|
||||
// }
|
||||
const item = entry.key_ptr.*;
|
||||
if (map[1] <= item and item <= map[1] + map[2]) {
|
||||
const offset = @as(isize, @intCast(map[0])) - @as(isize, @intCast(map[1]));
|
||||
const res: usize = @intCast(@as(isize, @intCast(item)) + offset);
|
||||
// std.debug.print("{d} => {d}\n", .{ item, res });
|
||||
try working_values.put(res, {});
|
||||
try to_delete.put(item, {});
|
||||
}
|
||||
}
|
||||
var td_it = to_delete.iterator();
|
||||
while (td_it.next()) |entry| {
|
||||
// std.debug.print("pop {d}\n", .{entry.key_ptr.*});
|
||||
_ = last_values.remove(entry.key_ptr.*);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var lv_it = last_values.iterator();
|
||||
while (lv_it.next()) |value| {
|
||||
low_loc = @min(low_loc, value.key_ptr.*);
|
||||
{
|
||||
std.debug.print("= seeding {d} =\n", .{seeds.len});
|
||||
var index: usize = 0;
|
||||
while (index < seeds.len) : (index += 2) {
|
||||
try ranges.append(.{
|
||||
.stage = 0,
|
||||
.range = .{
|
||||
.start = seeds[index],
|
||||
.end = seeds[index] + seeds[index + 1],
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return .{ .a = low_loc, .b = 0 };
|
||||
var current_stage: usize = 0;
|
||||
while (it.next()) |line| {
|
||||
if (line.len == 0) {
|
||||
std.debug.print("== finalise ==\n", .{});
|
||||
for (ranges.items, 0..) |item, index| {
|
||||
if (item.stage != current_stage) {
|
||||
ranges.items[index] = .{ .stage = current_stage, .range = item.range };
|
||||
}
|
||||
}
|
||||
mergeRanges(&ranges);
|
||||
} else if (mem.endsWith(u8, line, "map:")) {
|
||||
current_stage += 1;
|
||||
} else {
|
||||
std.debug.print("== stage {d} map {s} ==\n", .{ current_stage, line });
|
||||
const map_line = try util.parseIntsScalar(usize, alloc, line, .{});
|
||||
defer alloc.free(map_line);
|
||||
const map = Map{
|
||||
.offset = @as(isize, @intCast(map_line[0])) - @as(isize, @intCast(map_line[1])),
|
||||
.source = .{ .start = map_line[1], .end = map_line[1] + map_line[2] },
|
||||
};
|
||||
|
||||
var i: usize = ranges.items.len;
|
||||
while (i != 0) : (i -= 1) {
|
||||
if (ranges.items[i - 1].stage == current_stage) continue;
|
||||
const item = ranges.swapRemove(i - 1);
|
||||
std.debug.print("item {d}/{d} {d}..{d}\n", .{ i, ranges.items.len + 1, item.range.start, item.range.end });
|
||||
|
||||
if (item.range.intersect(.{ .start = 0, .end = map.source.start })) |section| {
|
||||
// Non-transitioning section.
|
||||
std.debug.print("=> s {d}..{d}\n", .{ section.start, section.end });
|
||||
try ranges.append(.{ .stage = item.stage, .range = section });
|
||||
}
|
||||
if (item.range.intersect(map.source)) |section| {
|
||||
// Transitioning section.
|
||||
const range = Range(usize){
|
||||
.start = @intCast(@as(isize, @intCast(section.start)) + map.offset),
|
||||
.end = @intCast(@as(isize, @intCast(section.end)) + map.offset),
|
||||
};
|
||||
std.debug.print("=> m {d}..{d}\n", .{ range.start, range.end });
|
||||
try ranges.append(.{
|
||||
.stage = current_stage,
|
||||
.range = range,
|
||||
});
|
||||
}
|
||||
if (item.range.intersect(.{ .start = map.source.end, .end = std.math.maxInt(usize) })) |section| {
|
||||
// Non-transitioning section.
|
||||
std.debug.print("=> e {d}..{d}\n", .{ section.start, section.end });
|
||||
try ranges.append(.{ .stage = item.stage, .range = section });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ranges.items) |item| {
|
||||
std.debug.print("{any}\n", .{item.range});
|
||||
lowest_location = @min(lowest_location, item.range.start);
|
||||
}
|
||||
|
||||
return lowest_location;
|
||||
}
|
||||
|
||||
test "silver" {
|
||||
@ -156,7 +218,7 @@ test "silver" {
|
||||
;
|
||||
_ = input;
|
||||
// const sln = try solve(std.testing.allocator, input);
|
||||
// try std.testing.expectEqual(@as(usize, 35), sln.a);
|
||||
// try std.testing.expectEqual(@as(usize, 35), sln);
|
||||
}
|
||||
|
||||
test "gold" {
|
||||
@ -196,5 +258,5 @@ test "gold" {
|
||||
\\56 93 4
|
||||
;
|
||||
const sln = try solve(std.testing.allocator, input);
|
||||
try std.testing.expectEqual(@as(usize, 46), sln.a);
|
||||
try std.testing.expectEqual(@as(usize, 46), sln);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user