You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
116 lines
3.3 KiB
Zig
116 lines
3.3 KiB
Zig
11 months ago
|
const std = @import("std");
|
||
|
|
||
|
const Lens = struct { label: []const u8, focalLength: u8 };
|
||
|
|
||
|
pub fn main() !void {
|
||
|
var content = @embedFile("data.txt");
|
||
|
|
||
|
var words = std.mem.split(u8, content, ",");
|
||
|
|
||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||
|
const allocator = gpa.allocator();
|
||
|
|
||
|
var boxes = std.AutoHashMap(u32, std.ArrayList(Lens)).init(allocator);
|
||
|
defer boxes.deinit();
|
||
|
|
||
|
var part1: u32 = 0;
|
||
|
while (words.next()) |w| {
|
||
|
// stupid last char thing
|
||
|
const word = if (w[w.len - 1] == 10) w[0 .. w.len - 2] else w;
|
||
|
|
||
|
// Part 1
|
||
|
part1 += hash(word);
|
||
|
|
||
|
// Part 2
|
||
|
const dash = std.mem.indexOf(u8, word, "-");
|
||
|
const equals = std.mem.indexOf(u8, word, "=");
|
||
|
const idx = dash orelse equals orelse unreachable;
|
||
|
const label = word[0..idx];
|
||
|
const box = hash(label);
|
||
|
std.debug.print("\nAfter \"{s}\":\n", .{word});
|
||
|
|
||
|
if (dash != null) {
|
||
|
// if dash, find the box
|
||
|
if (boxes.getPtr(box)) |list| {
|
||
|
// get the list, and find a lens with this label in it
|
||
|
var indexToRemove: ?usize = null;
|
||
|
for (list.items, 0..) |l, i| {
|
||
|
if (std.mem.eql(u8, l.label, label)) {
|
||
|
indexToRemove = i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// if it's there, remove it
|
||
|
if (indexToRemove) |i| {
|
||
|
_ = list.orderedRemove(i);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
// if equals, parse out parts, put it in the box
|
||
|
const focalLength = try std.fmt.parseInt(u8, word[idx + 1 ..], 10);
|
||
|
const lens = Lens{ .focalLength = focalLength, .label = label };
|
||
|
|
||
|
// does this list exist? use it. otherwise make a new one
|
||
|
var list = boxes.get(box) orelse std.ArrayList(Lens).init(allocator);
|
||
|
|
||
|
// find if this lens is already in the list
|
||
|
var dupIdx: ?usize = null;
|
||
|
for (list.items, 0..) |l, i| {
|
||
|
if (std.mem.eql(u8, l.label, label)) {
|
||
|
dupIdx = i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// if it is, replace it with the new lens
|
||
|
if (dupIdx) |i| {
|
||
|
try list.replaceRange(i, 1, &[_]Lens{lens});
|
||
|
} else {
|
||
|
try list.append(lens);
|
||
|
}
|
||
|
try boxes.put(box, list);
|
||
|
}
|
||
|
|
||
|
printBoxes(boxes);
|
||
|
}
|
||
|
|
||
|
std.debug.print("Part 1: {d}\n", .{part1});
|
||
|
|
||
|
var part2: usize = 0;
|
||
|
var it = boxes.iterator();
|
||
|
while (it.next()) |box| {
|
||
|
const boxNumber = box.key_ptr.*;
|
||
|
|
||
|
for (box.value_ptr.items, 0..) |lens, slotNumber| {
|
||
|
part2 += (boxNumber + 1) * (slotNumber + 1) * lens.focalLength;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
std.debug.print("Part 2: {d}\n", .{part2});
|
||
|
}
|
||
|
|
||
|
fn hash(word: []const u8) u32 {
|
||
|
var sum: u32 = 0;
|
||
|
for (word) |c| {
|
||
|
if (c == 10) {
|
||
|
break;
|
||
|
}
|
||
|
sum += c;
|
||
|
sum *= 17;
|
||
|
sum = sum % 256;
|
||
|
}
|
||
|
|
||
|
return sum;
|
||
|
}
|
||
|
|
||
|
fn printBoxes(boxes: std.AutoHashMap(u32, std.ArrayList(Lens))) void {
|
||
|
var it = boxes.iterator();
|
||
|
while (it.next()) |list| {
|
||
|
std.debug.print("Box {d}: ", .{list.key_ptr.*});
|
||
|
|
||
|
for (list.value_ptr.items) |lens| {
|
||
|
std.debug.print("[{s} {d}] ", .{ lens.label, lens.focalLength });
|
||
|
}
|
||
|
std.debug.print("\n", .{});
|
||
|
}
|
||
|
}
|