aoc/2020/2/main.zig

130 lines
3.5 KiB
Zig

const std = @import("std");
pub const Policy = struct {
min: u32 = 0,
max: u32 = 0,
value: u8,
password: []u8,
pub fn matches_policy_one(self: *Policy, s: []u8) bool {
var c : u32 = 0;
for(s) | v | {
if (@as(u8, v) == self.value) {
c += 1;
}
}
var valid = (c >= self.min and c <= self.max);
//std.log.debug("{} is {} for Policy {}-{} of {c} [{} found]",
// .{s, valid, self.min, self.max, self.value, c});
return valid;
}
pub fn matches_policy_two(self: *Policy, s: []u8) bool {
var n_matches : u32 = 0;
if (s[self.min-1] == self.value) {
n_matches += 1;
}
if (s[self.max-1] == self.value) {
n_matches += 1;
}
return n_matches == 1;
}
};
pub fn main() !void {
var allocator = std.heap.GeneralPurposeAllocator(.{}){};
var f = std.fs.File { .handle = try std.os.open("input", std.os.O_RDONLY, 0) };
var buffer : [1024]u8 = undefined;
var byte_buffer = std.ArrayList(u8).init(&allocator.allocator);
defer byte_buffer.deinit();
const stdout = std.io.getStdOut().writer();
var n_valid : u32 = 0;
var read = try f.read(&buffer);
std.log.info("Read {} bytes", .{read});
while (read != 0) {
for (buffer) | v, k | {
// We're through the read part of the buffer
if (k >= read) {
break;
}
if (v == '\n') {
var p = parse_policy(byte_buffer.items[0..]);
if (p.matches_policy_two(p.password)) {
n_valid += 1;
}
try stdout.print("{}-{} {c}: {}\n", .{p.min, p.max, p.value, p.password});
//std.log.debug("{}", .{x});
// Set the position back to zero, without freeing existing memory
byte_buffer.deinit();
byte_buffer = std.ArrayList(u8).init(&allocator.allocator);
continue;
}
try byte_buffer.append(v);
}
read = try f.read(&buffer);
std.log.info("Read {} bytes", .{read});
}
std.log.info("{} valid items", .{n_valid});
//part1(expenses.items[0..]);
//part2(expenses.items[0..]);
}
fn parse_policy(line: []u8) Policy {
var min : u32 = 0;
var max : u32 = 0;
var char : u8 = 0;
var pass : []u8 = undefined;
var start : usize = 0;
var got_min = false;
var got_max = false;
for (line) | v, k | {
if (v == '-') {
min = atoi(line[start..k]);
start = k + 1;
got_min = true;
}
if (v == ' ' and !got_max) {
max = atoi(line[start..k]);
start = k + 1;
got_max = true;
}
if (v == ':') {
char = line[start..k][0];
start = k + 2;
}
if (k == line.len-1) {
pass = line[start..];
}
}
return Policy {
.min = min,
.max = max,
.value = char,
.password = pass,
};
}
fn part2() void {
}
fn part1() void {
}
fn atoi(a: []u8) u32 {
var i : u32 = 0;
for(a) |v, k| {
if (! std.ascii.isDigit(v)) {
std.log.warn("Byte {x} is not a digit", .{v});
continue;
}
// 48 is '0' in ascii
std.debug.assert(v >= 48 and v < 58);
i += @as(u32, (v - 48) * std.math.pow(u32, 10, @intCast(u32, a.len - k - 1)));
}
//std.log.debug("{x} --> {}", .{a, i});
return i;
}