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

const PATH = "input/day10.txt";

const Str = []const u8;

pub fn first(allocator: ?std.mem.Allocator) anyerror!usize {
    const adapters = try parseInput(allocator.?, @embedFile(PATH));
    defer allocator.?.free(adapters);

    var one: usize = 0;
    var three: usize = 0;
    var idx: usize = 1;
    while (idx < adapters.len) : (idx += 1) {
        switch (adapters[idx] - adapters[idx - 1]) {
            1 => one += 1,
            3 => three += 1,
            else => unreachable,
        }
    }

    return one * three;
}

pub fn second(allocator: ?std.mem.Allocator) anyerror!usize {
    const adapters = try parseInput(allocator.?, @embedFile(PATH));
    defer allocator.?.free(adapters);

    var sum: usize = 1;

    var count: u3 = 0;
    var idx: usize = 1;
    while (idx < adapters.len) : (idx += 1) {
        const diff = adapters[idx] - adapters[idx - 1];
        if (diff == 1) {
            count += 1;
        } else {
            switch (count) {
                4 => sum *= 7, // ways to arrange 4 items
                3 => sum *= 4,
                2 => sum *= 2,
                1, 0 => {},
                else => unreachable,
            }
            count = 0;
        }
    }

    return sum;
}

fn parseInput(allocator: std.mem.Allocator, input: Str) ![]usize {
    var ret = std.ArrayList(usize).init(allocator);
    var lines = std.mem.tokenize(u8, input, "\n");

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

    try ret.append(0); // add charging outlet

    std.sort.sort(usize, ret.items, {}, comptime std.sort.asc(usize));

    try ret.append(ret.items[ret.items.len - 1] + 3); // add built-in adapter

    return ret.toOwnedSlice();
}

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

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