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

const INPUT = "14,3,1,0,9,5";

const Str = []const u8;

pub fn first(allocator: ?std.mem.Allocator) anyerror!usize {
    return getLast(allocator.?, INPUT, 2020, u11);
}

pub fn second(allocator: ?std.mem.Allocator) anyerror!usize {
    return getLast(allocator.?, INPUT, 30_000_000, u25);
}

fn getLast(allocator: std.mem.Allocator, input: Str, limit: usize, comptime ItemType: anytype) !usize {
    var spoken = std.ArrayList(ItemType).init(allocator);
    defer spoken.deinit();

    // Zero means the number was not spoken yet.
    try spoken.appendNTimes(0, limit);

    var last: ItemType = undefined;

    // Fill in starting numbers.
    var starting = std.mem.tokenize(u8, input, ",");
    var round: ItemType = 1;
    while (starting.next()) |st| : (round += 1) {
        const num = try std.fmt.parseUnsigned(ItemType, st, 0);
        spoken.items[num] = round;
        last = num;
    }

    // Van Eck Sequence
    round -= 1;
    while (round < limit) : (round += 1) {
        const next = round - if (spoken.items[last] != 0) spoken.items[last] else round;
        spoken.items[last] = round;
        last = next;
    }

    return @intCast(usize, last);
}

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

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