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

const PATH = "input/day06.txt";
const letters = 122 - 97 + 1; // ASCII code of 'z' and 'a'
const AnsType = u26;

pub fn first(allocator: ?std.mem.Allocator) anyerror!usize {
    _ = allocator;

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

    var answers: AnsType = 0;
    var sum: usize = 0;

    while (lines.next()) |line| {
        if (std.mem.eql(u8, line, "")) {
            sum += countOnes(answers);
            answers = 0;
        } else {
            for (line) |ch| {
                answers |= @as(AnsType, 1) << @intCast(u5, ch - 'a');
            }
        }
    }

    // handle last line...
    sum += countOnes(answers);

    return sum;
}

pub fn second(allocator: ?std.mem.Allocator) anyerror!usize {
    _ = allocator;

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

    var answers: AnsType = 0;
    var sum: usize = 0;
    var new_group: bool = true;

    while (lines.next()) |line| {
        if (std.mem.eql(u8, line, "")) {
            sum += countOnes(answers);
            answers = 0;
            new_group = true;
        } else {
            const prev = answers;
            answers = 0;

            for (line) |ch| {
                answers |= @as(AnsType, 1) << @intCast(u5, ch - 'a');
            }

            if (!new_group) {
                answers &= prev;
            }

            new_group = false;
        }
    }

    // handle last group...
    sum += countOnes(answers);

    return sum;
}

inline fn countOnes(ans: AnsType) usize {
    var ret: usize = 0;

    var i: u5 = 0; // <32
    while (i < letters) : (i += 1) {
        const mask = @as(AnsType, 1) << i;
        if (ans & mask != 0) ret += 1;
    }

    return ret;
}

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

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