aboutsummaryrefslogtreecommitdiffstats
path: root/day16
diff options
context:
space:
mode:
authorOrfeas <38209077+0xfea5@users.noreply.github.com>2023-12-16 11:20:06 +0200
committerOrfeas <38209077+0xfea5@users.noreply.github.com>2025-10-28 23:20:45 +0200
commit6fb83d92c250a9208148af283255ec5e0e9e9175 (patch)
tree9cf2e2416bcb0dbd6603fd190c4b55f3fb3f3907 /day16
parentday15 (diff)
downloadaoc23-6fb83d92c250a9208148af283255ec5e0e9e9175.tar.gz
aoc23-6fb83d92c250a9208148af283255ec5e0e9e9175.zip
day16
Diffstat (limited to 'day16')
-rw-r--r--day16/example.txt10
-rw-r--r--day16/solution.zig158
2 files changed, 168 insertions, 0 deletions
diff --git a/day16/example.txt b/day16/example.txt
new file mode 100644
index 0000000..d6805ce
--- /dev/null
+++ b/day16/example.txt
@@ -0,0 +1,10 @@
1.|...\....
2|.-.\.....
3.....|-...
4........|.
5..........
6.........\
7..../.\\..
8.-.-/..|..
9.|....-|.\
10..//.|....
diff --git a/day16/solution.zig b/day16/solution.zig
new file mode 100644
index 0000000..70da969
--- /dev/null
+++ b/day16/solution.zig
@@ -0,0 +1,158 @@
1const std = @import("std");
2const print = std.debug.print;
3const assert = std.debug.assert;
4const ArrayList = std.ArrayList;
5const HashMap = std.HashMap;
6const mem = std.mem;
7
8const fin = mem.trim(u8, @embedFile("./input.txt"), &std.ascii.whitespace);
9var gpa = std.heap.GeneralPurposeAllocator(.{}){};
10const allocator = gpa.allocator();
11
12const step = [_][2]i64{
13 [2]i64{ -1, 0 },
14 [2]i64{ 0, 1 },
15 [2]i64{ 1, 0 },
16 [2]i64{ 0, -1 },
17};
18
19const Beam = struct {
20 i: isize,
21 j: isize,
22 d: usize,
23
24 pub inline fn next(self: @This()) Beam {
25 return self.nextd(self.d);
26 }
27
28 pub inline fn prev(self: @This()) Beam {
29 return Beam{
30 .i = self.i - step[self.d][0],
31 .j = self.j - step[self.d][1],
32 .d = self.d,
33 };
34 }
35
36 pub inline fn nextd(self: @This(), d: usize) Beam {
37 return Beam{
38 .i = self.i + step[d][0],
39 .j = self.j + step[d][1],
40 .d = d,
41 };
42 }
43
44 pub const Ctx = struct {
45 pub fn hash(_: @This(), b: Beam) u64 {
46 return @bitCast(b.i << 16 | b.j << 8 | @as(isize, @bitCast(b.d)));
47 }
48
49 pub fn eql(_: @This(), lhs: Beam, rhs: Beam) bool {
50 return lhs.i == rhs.i and lhs.j == rhs.j and lhs.d == rhs.d;
51 }
52 };
53
54 // ignore direction when comparing beams
55 pub const Ctx2 = struct {
56 pub fn hash(_: @This(), b: Beam) u64 {
57 return @bitCast(b.i << 8 | b.j);
58 }
59
60 pub fn eql(_: @This(), lhs: Beam, rhs: Beam) bool {
61 const res = lhs.i == rhs.i and lhs.j == rhs.j;
62 return res;
63 }
64 };
65};
66
67var edgesVisited = HashMap(Beam, void, Beam.Ctx2, 80).init(allocator);
68
69fn dfs(grid: []const []const u8, start: Beam) !u64 {
70 if (edgesVisited.get(start) != null) {
71 return 0;
72 }
73 const w = grid[0].len;
74 const h = grid.len;
75 var beams = ArrayList(Beam).init(allocator);
76 var visited = HashMap(Beam, void, Beam.Ctx, 80).init(allocator);
77 var uniq = HashMap(Beam, void, Beam.Ctx2, 80).init(allocator);
78 defer {
79 beams.deinit();
80 uniq.deinit();
81 visited.deinit();
82 }
83
84 try beams.append(start);
85
86 while (beams.items.len > 0) {
87 var curr = beams.pop();
88 while (0 <= curr.i and curr.i < h and 0 <= curr.j and curr.j < w) {
89 if ((try visited.getOrPut(curr)).found_existing) {
90 break;
91 }
92 const c = grid[@bitCast(curr.i)][@bitCast(curr.j)];
93 switch (c) {
94 '|' => {
95 try beams.append(curr.nextd(2));
96 curr = curr.nextd(0);
97 },
98 '-' => {
99 try beams.append(curr.nextd(3));
100 curr = curr.nextd(1);
101 },
102 '\\' => {
103 const d = (curr.d + if (curr.d & 1 != 0) @as(usize, 1) else @as(usize, 3)) % 4;
104 curr = curr.nextd(d);
105 },
106 '/' => {
107 const d = (curr.d + if (curr.d & 1 != 0) @as(usize, 3) else @as(usize, 1)) % 4;
108 curr = curr.nextd(d);
109 },
110 '.' => {
111 curr = curr.next();
112 },
113 else => unreachable,
114 }
115 } else { // finished by hitting an edge
116 try edgesVisited.put(curr.prev(), {});
117 }
118 }
119
120 var it = visited.keyIterator();
121 while (it.next()) |k| {
122 try uniq.put(k.*, {});
123 }
124
125 return uniq.count();
126}
127
128pub fn solve(grid: []const []const u8) !void {
129 const h = grid.len;
130 const w = grid[0].len;
131 const part1 = try dfs(grid, Beam{ .i = 0, .j = 0, .d = 1 });
132
133 print("{d}\n", .{part1});
134
135 var part2: u64 = 0;
136 for (0..h) |i_| {
137 const i: i64 = @bitCast(i_);
138 part2 = @max(part2, try dfs(grid, .{ .i = i, .j = 0, .d = 1 }));
139 part2 = @max(part2, try dfs(grid, .{ .i = i, .j = @bitCast(w - 1), .d = 3 }));
140 }
141 for (0..w) |j_| {
142 const j: i64 = @bitCast(j_);
143 part2 = @max(part2, try dfs(grid, .{ .i = 0, .j = j, .d = 2 }));
144 part2 = @max(part2, try dfs(grid, .{ .i = @bitCast(h - 1), .j = j, .d = 0 }));
145 }
146
147 print("{d}\n", .{part2});
148}
149
150pub fn main() !void {
151 var splitLines = mem.splitScalar(u8, fin, '\n');
152 var grid = ArrayList([]const u8).init(allocator);
153
154 while (splitLines.next()) |line| {
155 try grid.append(line);
156 }
157 try solve(grid.items);
158}