aboutsummaryrefslogtreecommitdiffstats
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
parentimproving day7 solution (diff)
downloadaoc23-b961ad7dcf9aa0e2d2b09730704877eed2da68e7.tar.gz
aoc23-b961ad7dcf9aa0e2d2b09730704877eed2da68e7.zip
day8
-rw-r--r--day08/example1.txt9
-rw-r--r--day08/example2.txt5
-rw-r--r--day08/example3.txt10
-rw-r--r--day08/solution.zig131
4 files changed, 155 insertions, 0 deletions
diff --git a/day08/example1.txt b/day08/example1.txt
new file mode 100644
index 0000000..9029a1b
--- /dev/null
+++ b/day08/example1.txt
@@ -0,0 +1,9 @@
1RL
2
3AAA = (BBB, CCC)
4BBB = (DDD, EEE)
5CCC = (ZZZ, GGG)
6DDD = (DDD, DDD)
7EEE = (EEE, EEE)
8GGG = (GGG, GGG)
9ZZZ = (ZZZ, ZZZ)
diff --git a/day08/example2.txt b/day08/example2.txt
new file mode 100644
index 0000000..7d1b58d
--- /dev/null
+++ b/day08/example2.txt
@@ -0,0 +1,5 @@
1LLR
2
3AAA = (BBB, BBB)
4BBB = (AAA, ZZZ)
5ZZZ = (ZZZ, ZZZ)
diff --git a/day08/example3.txt b/day08/example3.txt
new file mode 100644
index 0000000..5b3fa58
--- /dev/null
+++ b/day08/example3.txt
@@ -0,0 +1,10 @@
1LR
2
311A = (11B, XXX)
411B = (XXX, 11Z)
511Z = (11B, XXX)
622A = (22B, XXX)
722B = (22C, 22C)
822C = (22Z, 22Z)
922Z = (22B, 22B)
10XXX = (XXX, XXX)
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}