Advent of Code 2020 solutions in Zig
const std = @import("std");

const PATH = "input/day09.txt";
const PREAMBLE = 25;

pub fn first(allocator: ?std.mem.Allocator) anyerror!usize {
    const input = try parseInput(allocator.?);
    defer allocator.?.free(input);

    return getInvalid(input);
}

fn getInvalid(data: []usize) usize {
    for (data) |num, idx| {
        if (idx < PREAMBLE) continue;
        if (!valid(data, idx, num)) {
            return num;
        }
    }
    unreachable;
}

inline fn valid(data: []usize, idx: usize, num: usize) bool {
    var x = idx - PREAMBLE;
    while (x < idx) : (x += 1) {
        var y = x + 1;
        while (y < idx) : (y += 1) {
            if (data[x] + data[y] == num) return true;
        }
    }
    return false;
}

pub fn second(allocator: ?std.mem.Allocator) anyerror!usize {
    const input = try parseInput(allocator.?);
    defer allocator.?.free(input);

    const weak = getInvalid(input);

    var x: usize = 0;
    while (x < input.len) : (x += 1) {
        var sum: usize = input[x];
        var min = sum;
        var max = sum;

        var y: usize = x + 1;
        while (y < input.len) : (y += 1) {
            sum += input[y];
            if (input[y] < min) min = input[y];
            if (input[y] > max) max = input[y];
            if (sum == weak) return max + min;
            if (sum > weak) break;
        }
    }

    unreachable;
}

fn parseInput(allocator: std.mem.Allocator) ![]usize {
    var ret = std.ArrayList(usize).init(allocator);

    const file = @embedFile(PATH);
    var lines = std.mem.tokenize(u8, file, "\n");

    while (lines.next()) |line| {
        try ret.append(try std.fmt.parseUnsigned(usize, line, 0));
    }

    return ret.toOwnedSlice();
}

test "day09a" {
    try std.testing.expectEqual(@as(usize, 1930745883), try first(std.testing.allocator));
}

test "day09b" {
    try std.testing.expectEqual(@as(usize, 268878261), try second(std.testing.allocator));
}