This repository has been archived on 2022-12-11. You can view files and clone it, but cannot push or open issues or pull requests.
aoc2022/03/1-2.zig

116 lines
3.6 KiB
Zig
Raw Permalink Normal View History

2022-12-03 08:27:12 +00:00
const std = @import("std");
// Wanted to implement both in a single modular and expansible way, so this is that.
const string = []const u8; // to simplify a bit
const Iterator = std.mem.SplitIterator(u8);
const stepFnType = *const fn (*Iterator, []string) ?[]string;
pub fn main() void {
2022-12-08 16:22:18 +00:00
const input = @embedFile("input");
2022-12-03 08:27:12 +00:00
// The fundamental difference lies in the way of processing the file,
// so we abstract that into a function to be able to pass its pointer.
std.debug.print("Part 1: {}\n", .{sumPriorities(input, stepInline, 2)});
std.debug.print("Part 2: {}\n", .{sumPriorities(input, stepInterline, 3)});
}
fn sumPriorities(input: string, stepFn: stepFnType, comptime amount: usize) usize {
var totalPriorities: usize = 0;
var iter = std.mem.split(u8, input, "\n");
// This buffer is needed to not allocate but it shouldn't be used directly
var _buffer = [_]string{undefined} ** amount;
// Use the stepper to divide into slices properly
while (stepFn(&iter, &_buffer)) |containers| {
// If it wasn't found just contine with the next line
const repe = findCommon(u8, containers) orelse continue;
// Convert to priority as specified
// 'a-z' -> '1-26', 'A-Z' -> '27-52'
const priority = if (repe >= 'a') repe - 'a' + 1 else repe - 'A' + 27;
totalPriorities += priority;
}
return totalPriorities;
}
// Helper to find the common needle in n haystacks
// Returns null if not found
fn findCommon(comptime T: type, haystacks: [][]const T) ?T {
// Why
if (haystacks.len <= 1) unreachable;
// We need to find a common needle for all of the haystacks.
// Compare each of the characters in the first one with
// the other ones in sequence.
//
// - If a match was found, jump to the next haystack.
// - If a match wasn't found, just to the next needle.
needle: for (haystacks[0]) |needle| {
// Semaphor to know if something was found when reaching
// the end of loops.
var found: bool = false;
haystack: for (haystacks[1..]) |haystack| {
found = false;
for (haystack) |blade| {
if (needle == blade) {
found = true;
break;
}
}
if (!found) {
// We didn't find the needle, try with another one
continue :needle;
} else {
// We did find it!
// Let's see if it's in the next haystack
continue :haystack;
}
}
// We found the needle in all haystacks, hooray!
if (found) return needle;
}
// We ran out of needles and nothing was found
return null;
}
// Steps the iterator and slices lines in the specified amount
fn stepInline(iter: *Iterator, buffer: []string) ?[]string {
// We reached the end
const line = iter.next() orelse return null;
// Line isn't valid
if (line.len == 0 or line.len % buffer.len != 0) return stepInline(iter, buffer);
const len = line.len / buffer.len;
for (buffer) |_, i| {
// Split line into slices into buffer
buffer[i] = line[i * len .. (i + 1) * len];
}
return buffer;
}
// Steps the iterator and puts whole lines in the specified amount
fn stepInterline(iter: *Iterator, buffer: []string) ?[]string {
for (buffer) |_, i| {
// No more lines
const line = iter.next() orelse return null;
// Invalid input, try next one
if (line.len <= 0) return stepInterline(iter, buffer);
buffer[i] = line;
}
return buffer;
}