From e0e2c81f6a6ef8b12445ddcf168e27572e326092 Mon Sep 17 00:00:00 2001 From: Jeremy Kaplan Date: Sat, 7 Dec 2024 22:00:32 -0800 Subject: [PATCH] 2024 Day 8 Part 2 --- 2024/src/aoc.zig | 22 +++++++++ 2024/src/day08.zig | 112 ++++++++++++++++++++++++++++++++------------- 2 files changed, 102 insertions(+), 32 deletions(-) diff --git a/2024/src/aoc.zig b/2024/src/aoc.zig index 57d4388..474cb91 100644 --- a/2024/src/aoc.zig +++ b/2024/src/aoc.zig @@ -82,3 +82,25 @@ pub fn parseAll( return all; } + +pub fn gcd(n: i32, m: i32) i32 { + var a = @abs(n); + var b = @abs(m); + + while (b != 0) { + const t = b; + b = a % b; + a = t; + } + + return @intCast(a); +} + +test "gcd" { + const expectEqual = std.testing.expectEqual; + + try expectEqual(2, gcd(2, 4)); + try expectEqual(1, gcd(2, 5)); + try expectEqual(1, gcd(-2, 3)); + try expectEqual(2, gcd(-2, -4)); +} diff --git a/2024/src/day08.zig b/2024/src/day08.zig index 3c4e6a8..bc278fa 100644 --- a/2024/src/day08.zig +++ b/2024/src/day08.zig @@ -18,49 +18,29 @@ pub fn main() !void { var grid = try Grid.parse(allocator, text); defer grid.deinit(); + var nodes = try NodeSet.make(allocator, grid); + defer nodes.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(allocator, grid)}); + try stdout.print("{d}\n", .{try part1(allocator, grid, nodes)}); + try bw.flush(); + + try stdout.print("{d}\n", .{try part2(allocator, grid, nodes)}); try bw.flush(); } -fn part1(allocator: Allocator, grid: Grid) !u64 { - var nodes = std.AutoHashMap(u8, aoc.AutoHashSet(Pos)).init(allocator); - defer nodes.deinit(); - defer { - var it = nodes.valueIterator(); - while (it.next()) |v| { - v.deinit(); - } - } - - { - var it = grid.iterator(); - while (it.next()) |mapEntry| { - const pos = mapEntry.key_ptr.*; - const id = mapEntry.value_ptr.*; - if (id == '.') { - continue; - } - - var nodeEntry = try nodes.getOrPut(id); - if (!nodeEntry.found_existing) { - nodeEntry.value_ptr.* = aoc.AutoHashSet(Pos).init(allocator); - } - try nodeEntry.value_ptr.put(pos); - } - } - +fn part1(allocator: Allocator, grid: Grid, nodes: NodeSet) !u64 { var antinodes = aoc.AutoHashSet(Pos).init(allocator); defer antinodes.deinit(); - var it = nodes.valueIterator(); - while (it.next()) |nodeSet| { - var aa = nodeSet.iterator(); + var it = nodes.map.valueIterator(); + while (it.next()) |positions| { + var aa = positions.iterator(); while (aa.next()) |a| { - var bb = nodeSet.iterator(); + var bb = positions.iterator(); while (bb.next()) |b| { if (a == b) { continue; @@ -81,6 +61,32 @@ fn part1(allocator: Allocator, grid: Grid) !u64 { return antinodes.count(); } +fn part2(allocator: Allocator, grid: Grid, nodes: NodeSet) !u64 { + var antinodes = aoc.AutoHashSet(Pos).init(allocator); + defer antinodes.deinit(); + + var it = nodes.map.valueIterator(); + while (it.next()) |positions| { + var aa = positions.iterator(); + while (aa.next()) |a| { + var bb = positions.iterator(); + while (bb.next()) |b| { + if (a == b) { + continue; + } + + const d = a.distance(b.*).unit(); + var pos = a.*; + while (grid.inBounds(pos)) : (pos = pos.add(d)) { + try antinodes.put(pos); + } + } + } + } + + return antinodes.count(); +} + const Pos = struct { r: i32, c: i32, @@ -112,6 +118,15 @@ const Pos = struct { const Delta = struct { dr: i32, dc: i32, + + fn unit(self: Delta) Delta { + const scale = aoc.gcd(self.dr, self.dc); + + return .{ + .dr = @divExact(self.dr, scale), + .dc = @divExact(self.dc, scale), + }; + } }; const Grid = struct { @@ -157,3 +172,36 @@ const Grid = struct { 0 <= pos.c and pos.c <= self.max.c; } }; + +const NodeSet = struct { + map: std.AutoHashMap(u8, aoc.AutoHashSet(Pos)), + + fn make(allocator: Allocator, grid: Grid) !NodeSet { + var map = std.AutoHashMap(u8, aoc.AutoHashSet(Pos)).init(allocator); + + var it = grid.iterator(); + while (it.next()) |mapEntry| { + const pos = mapEntry.key_ptr.*; + const id = mapEntry.value_ptr.*; + if (id == '.') { + continue; + } + + var nodeEntry = try map.getOrPut(id); + if (!nodeEntry.found_existing) { + nodeEntry.value_ptr.* = aoc.AutoHashSet(Pos).init(allocator); + } + try nodeEntry.value_ptr.put(pos); + } + + return .{ .map = map }; + } + + fn deinit(self: *NodeSet) void { + var it = self.map.valueIterator(); + while (it.next()) |v| { + v.deinit(); + } + self.map.deinit(); + } +};