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));
}