aoc2025 @ 860942b3aa8cfdf1a9a2e6569b54d3bf5c24c666

  1diff --git a/src/day2.zig b/src/day2.zig
  2new file mode 100644
  3index 0000000000000000000000000000000000000000..54ded3d37f9fe656223e3120b2a6fb72457d51ba
  4--- /dev/null
  5+++ b/src/day2.zig
  6@@ -0,0 +1,134 @@
  7+const std = @import("std");
  8+
  9+pub fn pt1(comptime input: []const u8) u64 {
 10+    const r = input[0 .. input.len - 1];
 11+    var ranges = std.mem.splitScalar(u8, r, ',');
 12+
 13+    var count: u64 = 0;
 14+    while (ranges.next()) |l| {
 15+        if (l.len == 0) {
 16+            return count;
 17+        }
 18+
 19+        var range = parseRange(l);
 20+        while (range.next()) |v| {
 21+            if (isRange(v)) {
 22+                count += v;
 23+            }
 24+        }
 25+    }
 26+    return count;
 27+}
 28+
 29+pub fn pt2(comptime input: []const u8) u64 {
 30+    const r = input[0 .. input.len - 1];
 31+    var ranges = std.mem.splitScalar(u8, r, ',');
 32+
 33+    var count: u64 = 0;
 34+    while (ranges.next()) |l| {
 35+        if (l.len == 0) {
 36+            return count;
 37+        }
 38+
 39+        var range = parseRange(l);
 40+        while (range.next()) |v| {
 41+            if (isRangeN(v)) {
 42+                count += v;
 43+            }
 44+        }
 45+    }
 46+    return count;
 47+}
 48+
 49+var buf: [20]u8 = undefined;
 50+
 51+fn isRangeN(v: u64) bool {
 52+    const str = std.fmt.bufPrint(&buf, "{d}", .{v}) catch unreachable;
 53+    for (1..str.len) |s| {
 54+        // We can't check if this batch can not evenly chunked.
 55+        if (@mod(str.len, s) != 0) {
 56+            continue;
 57+        }
 58+
 59+        const c = str.len / s; // size on the chunk
 60+        const p = str[0..s]; // first chunk as reference for eql
 61+        var m = true; // flag that says if something went wrong (if wrong set false)
 62+
 63+
 64+        for (1..c) |i| {
 65+            const sub_str = str[i * s .. ((1 + i) * s)];
 66+            if (!std.mem.eql(u8, p, sub_str)) {
 67+                m = false;
 68+                break;
 69+            }
 70+        }
 71+
 72+        if (m) return true;
 73+    }
 74+
 75+    return false;
 76+}
 77+
 78+fn isRange(v: u64) bool {
 79+    const str = std.fmt.bufPrint(&buf, "{d}", .{v}) catch unreachable;
 80+
 81+    if ((str.len % 2) != 0) {
 82+        return false;
 83+    }
 84+
 85+    const mid = str.len / 2;
 86+
 87+    for (0..mid) |i| {
 88+        if (str[i] != str[i + mid]) {
 89+            return false;
 90+        }
 91+    }
 92+
 93+    return true;
 94+}
 95+
 96+const Range = struct {
 97+    from: u64 = 0,
 98+    to: u64 = 0,
 99+    index: u64 = 0,
100+
101+    pub fn next(self: *Range) ?u64 {
102+        const to = self.from + self.index;
103+        if (to > self.to) {
104+            return null;
105+        }
106+
107+        self.index += 1;
108+        return to;
109+    }
110+};
111+
112+fn parseRange(range_str: []const u8) Range {
113+    var range: Range = .{};
114+    var iter = std.mem.splitScalar(u8, range_str, '-');
115+
116+    var i: u64 = 0;
117+    while (iter.next()) |v| {
118+        if (i == 0) {
119+            range.from = std.fmt.parseInt(u64, v, 10) catch unreachable;
120+        } else if (i == 1) {
121+            range.to = std.fmt.parseInt(u64, v, 10) catch unreachable;
122+        } else {
123+            break;
124+        }
125+
126+        i += 1;
127+    }
128+
129+    return range;
130+}
131+
132+test "Day 2 part 1" {
133+    const res = pt1(@embedFile("./input/day2"));
134+    try std.testing.expect(res == 55916882972);
135+}
136+
137+test "Day 2 part 2" {
138+    const res = pt2(@embedFile("./input/day2"));
139+    try std.testing.expect(res == 76169125915);
140+}
141diff --git a/src/input/day2 b/src/input/day2
142new file mode 100644
143index 0000000000000000000000000000000000000000..e25e1dfab5ef285fcab6de587bba923f671d1cd2
144Binary files /dev/null and b/src/input/day2 differ
145diff --git a/src/main.zig b/src/main.zig
146index 5e3e5db784a782f83dbbeb21cee134173fdc4a37..a4db764ce025c1f5602895b2bd39383d4d53333f 100644
147--- a/src/main.zig
148+++ b/src/main.zig
149@@ -1,19 +1,27 @@
150 const std = @import("std");
151 const day1 = @import("day1.zig");
152+const day2 = @import("day2.zig");
153 
154 pub export fn main() void {
155-    if (std.os.argv.len != 2) {
156-        std.debug.print("Invalid day", .{});
157-    }
158+    for (1..std.os.argv.len) |i| {
159+        const day = std.mem.span(std.os.argv[i]);
160 
161-    const day = std.mem.span(std.os.argv[1]);
162+        if (std.mem.eql(u8, "day1", day)) {
163+            print(day1.pt1(@embedFile("./input/day1")));
164+            print(day1.pt2(@embedFile("./input/day1")));
165+        } else if (std.mem.eql(u8, "day2", day)) {
166+            print(day2.pt1(@embedFile("./input/day2")));
167+            print(day2.pt2(@embedFile("./input/day2")));
168+        }
169+    }
170+}
171 
172-    if (std.mem.eql(u8, "--day1", day)) {
173-        const res1 = day1.pt1(@embedFile("./input/day1"));
174-        std.debug.print("{d}\n", .{res1});
175-        const res2 = day1.pt2(@embedFile("./input/day1"));
176-        std.debug.print("{d}\n", .{res2});
177+fn print(res: anytype) void {
178+    const ArgsType = @TypeOf(res);
179+    const res_type_info = @typeInfo(ArgsType);
180+    if (res_type_info == .int) {
181+        std.debug.print("{d}\n", .{res});
182     } else {
183-        std.debug.print("Invalid day", .{});
184+        @compileError("print not implemented for this type");
185     }
186 }