aboutsummaryrefslogtreecommitdiffstats
path: root/day08/solution.zig
diff options
context:
space:
mode:
authorOrfeas <38209077+0xfea5@users.noreply.github.com>2023-12-08 19:39:29 +0200
committerOrfeas <38209077+0xfea5@users.noreply.github.com>2025-10-28 23:20:45 +0200
commitb961ad7dcf9aa0e2d2b09730704877eed2da68e7 (patch)
tree43ae0da1254bb4a6d54df4a70380c19731adb05b /day08/solution.zig
parentimproving day7 solution (diff)
downloadaoc23-b961ad7dcf9aa0e2d2b09730704877eed2da68e7.tar.gz
aoc23-b961ad7dcf9aa0e2d2b09730704877eed2da68e7.zip
day8
Diffstat (limited to 'day08/solution.zig')
-rw-r--r--day08/solution.zig131
1 files changed, 131 insertions, 0 deletions
diff --git a/day08/solution.zig b/day08/solution.zig
new file mode 100644
index 0000000..75e6e73
--- /dev/null
+++ b/day08/solution.zig
@@ -0,0 +1,131 @@
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 Rule = struct {
13 key: u32,
14 left: u32,
15 right: u32,
16
17 pub fn endsWith(key: u32, e: u8) bool {
18 return key & 0b1111_1111 == e;
19 }
20
21 pub fn hash(s: []const u8) u32 {
22 assert(s.len == 3);
23 return s[2] | (@as(u32, s[1]) << 8) | (@as(u32, s[0]) << 16);
24 }
25
26 pub fn init(text: []const u8) Rule {
27 var splitTokens = mem.splitAny(u8, text, " =(),");
28 var nonEmpty = [3]u32{ undefined, undefined, undefined };
29 var i: usize = 0;
30
31 while (splitTokens.next()) |tok| {
32 if (tok.len != 3) {
33 continue;
34 }
35 nonEmpty[i] = hash(tok);
36 i += 1;
37 }
38
39 assert(i == 3);
40
41 return Rule{
42 .key = nonEmpty[0],
43 .left = nonEmpty[1],
44 .right = nonEmpty[2],
45 };
46 }
47};
48
49const RuleCtx = struct {
50 pub fn hash(_: @This(), K: u32) u64 {
51 return K;
52 }
53
54 pub fn eql(_: @This(), K1: u32, K2: u32) bool {
55 return K1 == K2;
56 }
57};
58
59const RuleMap = HashMap(u32, Rule, RuleCtx, 80);
60
61fn evaluate(instructions: []const u8, rules: RuleMap, start: u32, isPart1: bool) u64 {
62 const zzz = Rule.hash("ZZZ");
63 var curr = start;
64 var steps: u64 = 0;
65
66 while (if (isPart1) (curr != zzz) else !Rule.endsWith(curr, 'Z')) : (steps += 1) {
67 const in = instructions[steps % instructions.len];
68
69 curr = switch (in) {
70 'L' => rules.get(curr).?.left,
71 'R' => rules.get(curr).?.right,
72 else => unreachable,
73 };
74 }
75
76 return steps;
77}
78
79pub fn part1(instructions: []const u8, rules: RuleMap) void {
80 const ans = evaluate(instructions, rules, Rule.hash("AAA"), true);
81
82 print("{d}\n", .{ans});
83}
84
85fn gcd(a_: u64, b_: u64) u64 {
86 var a = a_;
87 var b = b_;
88 while (a != b) {
89 if (a > b) {
90 a -= b;
91 } else {
92 b -= a;
93 }
94 }
95 return a;
96}
97
98fn lcm(a: u64, b: u64) u64 {
99 return a / gcd(a, b) * b;
100}
101
102pub fn part2(instructions: []const u8, rules: RuleMap) void {
103 var ans: u64 = 1;
104 var keyIt = rules.keyIterator();
105
106 while (keyIt.next()) |k| {
107 if (Rule.endsWith(k.*, 'A')) {
108 const steps = evaluate(instructions, rules, k.*, false);
109
110 ans = lcm(ans, steps);
111 }
112 }
113
114 print("{d}\n", .{ans});
115}
116
117pub fn main() !void {
118 var splitLines = mem.splitScalar(u8, fin, '\n');
119 var rules = RuleMap.init(allocator);
120
121 var instructions = splitLines.next().?;
122 _ = splitLines.next();
123
124 while (splitLines.next()) |line| {
125 const R = Rule.init(line);
126 try rules.put(R.key, R);
127 }
128
129 part1(instructions, rules);
130 part2(instructions, rules);
131}