- commit
- 9d35807060ab1c4d228c2e59aea4dd280fe11cb9
- parent
- 74ebf5fcd08a57630900202f795bded771607b3c
- Author
- Tobias Bengfort <tobias.bengfort@posteo.de>
- Date
- 2025-12-02 22:25
2025-12-02
Diffstat
| A | 2025/02/input.txt | 1 | + |
| A | 2025/02/solution.zig | 90 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | 2025/02/test.txt | 1 | + |
3 files changed, 92 insertions, 0 deletions
diff --git a/2025/02/input.txt b/2025/02/input.txt
@@ -0,0 +1 @@ -1 1 52-75,71615244-71792700,89451761-89562523,594077-672686,31503-39016,733-976,1-20,400309-479672,458-635,836793365-836858811,3395595155-3395672258,290-391,5168-7482,4545413413-4545538932,65590172-65702074,25-42,221412-256187,873499-1078482,118-154,68597355-68768392,102907-146478,4251706-4487069,64895-87330,8664371543-8664413195,4091-5065,537300-565631,77-115,83892238-83982935,6631446-6694349,1112-1649,7725-9776,1453397-1493799,10240-12328,15873-20410,1925-2744,4362535948-4362554186,3078725-3256936,710512-853550,279817-346202,45515-60928,3240-3952
diff --git a/2025/02/solution.zig b/2025/02/solution.zig
@@ -0,0 +1,90 @@
-1 1 const std = @import("std");
-1 2
-1 3 const Error = error{IndexError};
-1 4
-1 5 fn splitOnce(s: []u8, sep: u8) ![2][]u8 {
-1 6 const i = std.mem.indexOfScalar(u8, s, sep) orelse return Error.IndexError;
-1 7 return .{ s[0..i], s[i + 1 ..] };
-1 8 }
-1 9
-1 10 fn takeRange(r: *std.Io.Reader) ![]u8 {
-1 11 const s = r.takeDelimiterInclusive(',') catch |err| switch (err) {
-1 12 error.EndOfStream => try r.takeDelimiterInclusive('\n'),
-1 13 else => |e| return e,
-1 14 };
-1 15 return s[0 .. s.len - 1];
-1 16 }
-1 17
-1 18 fn getDigits(i: usize) usize {
-1 19 const f: f64 = @floatFromInt(i);
-1 20 const digits = @floor(@log10(f)) + 1;
-1 21 return @intFromFloat(digits);
-1 22 }
-1 23
-1 24 fn getMask(digits: usize, repeats: usize) usize {
-1 25 // examples:
-1 26 // - a number with 6 digits and 2 repeats has the form 100..999 * 1001
-1 27 // - a number with 8 digits and 4 repeats has the form 10..99 * 1010101
-1 28
-1 29 var mask: usize = 1;
-1 30 for (1..repeats) |_| {
-1 31 mask = mask * std.math.pow(usize, 10, digits / repeats) + 1;
-1 32 }
-1 33 return mask;
-1 34 }
-1 35
-1 36 pub fn main() !void {
-1 37 const path: [:0]const u8 = std.mem.span(std.os.argv[1]);
-1 38 var file = try std.fs.cwd().openFile(path, .{});
-1 39 defer file.close();
-1 40
-1 41 var buffer: [64]u8 = undefined;
-1 42 var reader = file.reader(&buffer);
-1 43
-1 44 var part1: usize = 0;
-1 45 var part2: usize = 0;
-1 46
-1 47 while (takeRange(&reader.interface)) |line| {
-1 48 const s1, const s2 = try splitOnce(line, '-');
-1 49 const start = try std.fmt.parseInt(usize, s1, 10);
-1 50 const end = try std.fmt.parseInt(usize, s2, 10);
-1 51 std.debug.assert(start <= end);
-1 52
-1 53 for (getDigits(start)..getDigits(end) + 1) |digits| {
-1 54 for (2..digits + 1) |repeats| {
-1 55 if (digits % repeats != 0) {
-1 56 continue;
-1 57 }
-1 58
-1 59 const mask = getMask(digits, repeats);
-1 60 const min = std.math.pow(usize, 10, digits / repeats - 1);
-1 61 const minValue = @max(
-1 62 min,
-1 63 try std.math.divCeil(usize, start, mask),
-1 64 );
-1 65 const maxValue = @min(
-1 66 min * 10 - 1,
-1 67 try std.math.divFloor(usize, end, mask),
-1 68 );
-1 69 valueloop: for (minValue..maxValue + 1) |value| {
-1 70 const result = value * mask;
-1 71 for (2..repeats) |prevRepeats| {
-1 72 if (result % getMask(digits, prevRepeats) == 0) {
-1 73 continue :valueloop;
-1 74 }
-1 75 }
-1 76 part2 += result;
-1 77 if (repeats == 2) {
-1 78 part1 += result;
-1 79 }
-1 80 }
-1 81 }
-1 82 }
-1 83 } else |err| switch (err) {
-1 84 error.EndOfStream => {},
-1 85 else => |e| return e,
-1 86 }
-1 87
-1 88 std.debug.print("part1: {}\n", .{part1});
-1 89 std.debug.print("part2: {}\n", .{part2});
-1 90 }
diff --git a/2025/02/test.txt b/2025/02/test.txt
@@ -0,0 +1 @@ -1 1 11-22,95-115,998-1012,1188511880-1188511890,222220-222224,1698522-1698528,446443-446449,38593856-38593862,565653-565659,824824821-824824827,2121212118-2121212124