Watch
1
0
Fork
You've already forked advent-of-code
0

2024 Day 5 Zig backport

This commit is contained in:
Jeremy Kaplan 2024-12-04 22:20:28 -08:00
commit 4279067eae
2 changed files with 238 additions and 0 deletions

View file

@ -28,3 +28,36 @@ pub const Lines = struct {
} }
} }
}; };
pub fn AutoHashSet(comptime T: type) type {
const Empty = struct {};
const Map = std.AutoHashMap(T, Empty);
return struct {
map: Map,
const Self = @This();
pub fn init(allocator: std.mem.Allocator) Self {
return .{
.map = Map.init(allocator),
};
}
pub fn deinit(self: *Self) void {
self.map.deinit();
}
pub fn put(self: *Self, v: T) !void {
return self.map.put(v, .{});
}
pub fn contains(self: Self, v: T) bool {
return self.map.contains(v);
}
pub fn valueIterator(self: Self) Map.KeyIterator {
return self.map.keyIterator();
}
};
}

205
2024/src/day05.zig Normal file
View file

@ -0,0 +1,205 @@
const std = @import("std");
const aoc = @import("aoc.zig");
const Allocator = std.mem.Allocator;
const ArrayList = std.ArrayList;
pub fn main() !void {
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .{};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const file = try std.fs.cwd().openFile("input/day05.txt", .{});
defer file.close();
const text = try file.readToEndAlloc(allocator, comptime 1 << 30);
defer allocator.free(text);
var input = try Input.parse(allocator, text);
defer input.deinit();
const stdout_file = std.io.getStdOut().writer();
var bw = std.io.bufferedWriter(stdout_file);
const stdout = bw.writer();
try stdout.print("{d}\n", .{try part1(input)});
try bw.flush();
try stdout.print("{d}\n", .{try part2(input)});
try bw.flush();
}
const Input = struct {
rules: ArrayList(Rule),
updates: ArrayList(Update),
constraints: std.AutoHashMap(u32, Constraints),
fn deinit(self: *Input) void {
self.rules.deinit();
for (self.updates.items) |update| {
update.deinit();
}
self.updates.deinit();
var it = self.constraints.valueIterator();
while (it.next()) |value| {
value.before.deinit();
value.after.deinit();
}
self.constraints.deinit();
}
fn parse(alloc: Allocator, text: []const u8) !Input {
var blocks = std.mem.tokenizeSequence(u8, text, "\n\n");
var rule_lines = std.mem.tokenizeScalar(u8, blocks.next().?, '\n');
var rules = ArrayList(Rule).init(alloc);
while (rule_lines.next()) |line| {
try rules.append(try Rule.parse(line));
}
var update_lines = std.mem.tokenizeScalar(u8, blocks.next().?, '\n');
var updates = ArrayList(Update).init(alloc);
while (update_lines.next()) |line| {
try updates.append(try Update.parse(alloc, line));
}
var constraints = std.AutoHashMap(u32, Constraints).init(alloc);
for (rules.items) |rule| {
{
var c = try constraints.getOrPut(rule.x);
if (!c.found_existing) {
c.value_ptr.* = Constraints.init(alloc);
}
try c.value_ptr.after.put(rule.y);
}
{
var c = try constraints.getOrPut(rule.y);
if (!c.found_existing) {
c.value_ptr.* = Constraints.init(alloc);
}
try c.value_ptr.before.put(rule.x);
}
}
return .{
.rules = rules,
.updates = updates,
.constraints = constraints,
};
}
};
const Rule = struct {
x: u32,
y: u32,
fn parse(line: []const u8) !Rule {
var it = std.mem.tokenizeScalar(u8, line, '|');
const x = try std.fmt.parseInt(u32, it.next().?, 10);
const y = try std.fmt.parseInt(u32, it.next().?, 10);
return .{
.x = x,
.y = y,
};
}
};
const Update = struct {
pages: ArrayList(u32),
fn deinit(self: Update) void {
self.pages.deinit();
}
fn parse(alloc: Allocator, line: []const u8) !Update {
var pages = ArrayList(u32).init(alloc);
var it = std.mem.tokenizeScalar(u8, line, ',');
while (it.next()) |p| {
const page = try std.fmt.parseInt(u32, p, 10);
try pages.append(page);
}
return .{
.pages = pages,
};
}
fn valid(self: Update, constraints: std.AutoHashMap(u32, Constraints)) bool {
const items = self.pages.items;
for (items[0..(items.len - 1)], items[1..]) |x, y| {
if (constraints.get(x)) |c| {
if (!c.after.contains(y)) {
return false;
}
}
}
return true;
}
};
const Constraints = struct {
before: aoc.AutoHashSet(u32),
after: aoc.AutoHashSet(u32),
fn init(alloc: Allocator) Constraints {
return .{
.before = aoc.AutoHashSet(u32).init(alloc),
.after = aoc.AutoHashSet(u32).init(alloc),
};
}
fn deinit(self: *Constraints) void {
self.before.deinit();
self.before = undefined;
self.after.deinit();
self.after = undefined;
}
};
fn part1(input: Input) !u32 {
var sum: u32 = 0;
for (input.updates.items) |u| {
if (u.valid(input.constraints)) {
sum += u.pages.items[u.pages.items.len / 2];
}
}
return sum;
}
const FixUpdate = struct {
constraints: std.AutoHashMap(u32, Constraints),
fn lessThan(self: FixUpdate, x: u32, y: u32) bool {
if (self.constraints.get(x)) |c| {
return c.after.contains(y);
}
return false;
}
};
fn part2(input: Input) !u32 {
var sum: u32 = 0;
for (input.updates.items) |u| {
if (u.valid(input.constraints)) {
continue;
}
std.mem.sort(
u32,
u.pages.items,
FixUpdate{ .constraints = input.constraints },
FixUpdate.lessThan,
);
sum += u.pages.items[u.pages.items.len / 2];
}
return sum;
}