119 lines
3.8 KiB
Zig
119 lines
3.8 KiB
Zig
const std = @import("std");
|
|
|
|
pub fn main() anyerror!void {
|
|
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
|
defer arena.deinit();
|
|
var gpa = &arena.allocator;
|
|
|
|
var records = try read_records("input", gpa);
|
|
|
|
// part 1
|
|
var yes_per_group = std.ArrayList(u32).init(gpa);
|
|
var yeses : u32 = 0;
|
|
for (records.items) |r| {
|
|
var map = std.hash_map.AutoHashMap(u8, bool).init(gpa);
|
|
defer map.deinit();
|
|
try map.ensureCapacity(26);
|
|
|
|
for (r) |c| {
|
|
if (std.ascii.isAlpha(c)) {
|
|
map.putAssumeCapacity(c, true);
|
|
}
|
|
}
|
|
var count = map.count();
|
|
std.log.debug("{} yeses in group '{}'", .{count, r});
|
|
try yes_per_group.append(count);
|
|
yeses += count;
|
|
}
|
|
std.log.info("{} yeses across {} groups", .{yeses, yes_per_group.items.len});
|
|
|
|
// part 2
|
|
const one :u26 = comptime 1;
|
|
var and_yeses : u32 = 0;
|
|
for (records.items) |r| {
|
|
var it = std.mem.tokenize(r, " ");
|
|
var state : u26 = std.math.maxInt(u26);
|
|
while (it.next()) |answer| {
|
|
var person_yeses : u26 = 0;
|
|
for (answer) |c| {
|
|
if (std.ascii.isAlpha(c)) {
|
|
person_yeses |= (one << @intCast(u5, (c-97)));
|
|
}
|
|
}
|
|
//std.log.debug("{x} <-- {}", .{person_yeses, answer});
|
|
state &= person_yeses;
|
|
}
|
|
//std.log.debug("{x}", .{state});
|
|
var count = count_one_bits(state);
|
|
//std.log.debug("{} and-yeses in group '{}'", .{count, r});
|
|
and_yeses += count;
|
|
}
|
|
std.log.info("{} and-yeses across {} groups", .{and_yeses, yes_per_group.items.len});
|
|
}
|
|
|
|
fn count_one_bits(a: u26) u32 {
|
|
var i : u5 = 0;
|
|
var one : u26 = 1;
|
|
var count : u32 = 0;
|
|
while (i < 26) : (i += 1) {
|
|
var b : u26 = one << i;
|
|
if ((a & b) == b) {
|
|
count +=1;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
fn read_records(filename: []const u8, allocator: *std.mem.Allocator) !std.ArrayList([]u8) {
|
|
var file = try std.fs.cwd().openFile(filename, .{});
|
|
var reader = file.reader();
|
|
|
|
var records = std.ArrayList([]u8).init(allocator);
|
|
var record = std.ArrayList(u8).init(allocator);
|
|
var n_newlines : u32 = 0;
|
|
var just_had_newline = false;
|
|
const state = enum {
|
|
AddingData,
|
|
CheckingNewline,
|
|
RecordEnd,
|
|
};
|
|
var current_state = state.AddingData;
|
|
while(true) {
|
|
var n = reader.readByte() catch |err| {
|
|
// Finalize record
|
|
try records.append(try allocator.dupe(u8, record.items[0..record.items.len]));
|
|
//std.log.debug("Found record: '{}'", .{record.items});
|
|
record.deinit();
|
|
record = std.ArrayList(u8).init(allocator);
|
|
std.mem.set(u8, record.items, 0);
|
|
break;
|
|
};
|
|
if (n == '\n') {
|
|
if (current_state == state.CheckingNewline) {
|
|
current_state = state.RecordEnd;
|
|
// Finalize record
|
|
try records.append(try allocator.dupe(u8, record.items[0..record.items.len]));
|
|
//std.log.debug("Found record: '{}'", .{record.items});
|
|
record.deinit();
|
|
record = std.ArrayList(u8).init(allocator);
|
|
std.mem.set(u8, record.items, 0);
|
|
current_state = state.AddingData;
|
|
continue;
|
|
}
|
|
else {
|
|
current_state = state.CheckingNewline;
|
|
// whitespace can always be added
|
|
try record.append(' ');
|
|
continue;
|
|
}
|
|
}
|
|
else {
|
|
if (current_state == state.CheckingNewline) {
|
|
current_state = state.AddingData;
|
|
}
|
|
try record.append(n);
|
|
}
|
|
}
|
|
std.log.debug("Found {} records", .{records.items.len});
|
|
return records;
|
|
}
|