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