summaryrefslogtreecommitdiff
path: root/aoc25/src/day2.zig
blob: a5bb3db4b491b4d7997ee26764fcee899b29e25b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
const std = @import("std");

const test_input =
    \\11-22,95-115,998-1012,1188511880-1188511890,222220-222224,1698522-1698528,446443-446449,38593856-38593862,565653-565659,824824821-824824827,2121212118-2121212124
    \\
;

test part1 {
    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
    defer arena.deinit();
    const allocator = arena.allocator();

    try std.testing.expectEqual(1227775554, try part1(allocator, try parse(allocator, test_input)));
}

test part2 {
    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
    defer arena.deinit();
    const allocator = arena.allocator();

    try std.testing.expectEqual(4174379265, try part2(allocator, try parse(allocator, test_input)));
}

const Input = []struct {
    from: u64,
    to: u64,
};

pub fn parse(allocator: std.mem.Allocator, input: []const u8) !Input {
    var spans = std.mem.splitScalar(u8, input, ',');

    var parsed = try std.ArrayList(@typeInfo(Input).pointer.child).initCapacity(allocator, 0);

    while (spans.next()) |span_| {
        var span = if (std.mem.endsWith(u8, span_, "\n")) span_[0 .. span_.len - 1] else span_;
        const dash = std.mem.indexOfScalar(u8, span, '-') orelse return error.InvalidInput;
        const from = try std.fmt.parseInt(u64, span[0..dash], 10);
        const to = try std.fmt.parseInt(u64, span[dash + 1 ..], 10);
        try parsed.append(allocator, .{ .from = from, .to = to });
    }

    return parsed.toOwnedSlice(allocator);
}

pub fn part1(allocator: std.mem.Allocator, input: Input) !usize {
    var allocating_writer = std.io.Writer.Allocating.init(allocator);
    const writer = &allocating_writer.writer;
    var answer: usize = 0;
    for (input) |span| {
        for (span.from..span.to + 1) |n| {
            allocating_writer.clearRetainingCapacity();
            try writer.print("{}", .{n});
            const written = allocating_writer.written();
            if (written.len % 2 == 1) continue;
            const len = written.len / 2;
            if (!std.mem.eql(u8, written[0..len], written[len..])) continue;
            // std.debug.print("{}\n", .{n});
            answer += n;
        }
    }
    return answer;
}

pub fn part2(allocator: std.mem.Allocator, input: Input) !usize {
    var allocating_writer = std.io.Writer.Allocating.init(allocator);
    const writer = &allocating_writer.writer;
    var answer: usize = 0;
    for (input) |span| {
        n: for (span.from..span.to + 1) |n| {
            allocating_writer.clearRetainingCapacity();
            try writer.print("{}", .{n});
            const written = allocating_writer.written();
            for (2..written.len + 1) |repetitions| {
                if (written.len % repetitions != 0) continue;
                const len = written.len / repetitions;
                const first = written[0..len];
                var windows = std.mem.window(u8, written, len, len);
                while (windows.next()) |window| {
                    if (!std.mem.eql(u8, first, window)) break;
                } else { // all were equal
                    answer += n;
                    continue :n;
                }
            }
        }
    }
    return answer;
}