const std = @import("std"); const print = std.debug.print; const assert = std.debug.assert; const ArrayList = std.ArrayList; const HashMap = std.HashMap; const mem = std.mem; const fin = mem.trim(u8, @embedFile("./input.txt"), &std.ascii.whitespace); var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator(); fn hash(s: []const u8) u64 { var h: u64 = 0; for (s) |c| { h += c; h *= 17; h %= 256; } return @bitCast(h); } fn part1(strings: []const []const u8) void { var ans: u64 = 0; for (strings) |s| { ans += hash(s); } print("{d}\n", .{ans}); } const Pair = struct { label: []const u8, value: u64, }; fn part2(strings: []const []const u8) !void { var map: [256]ArrayList(Pair) = undefined; for (&map) |*e| { e.* = ArrayList(Pair).init(allocator); } for (strings) |s| { const action = s[mem.indexOfAny(u8, s, "-=").?]; var toks = mem.tokenizeAny(u8, s, "-="); const label = toks.next().?; const value = toks.next(); if (action == '=') { const v = try std.fmt.parseInt(u64, value.?, 10); const m = &map[hash(label)]; for (m.items) |*i| { if (mem.eql(u8, i.label, label)) { i.value = v; break; } } else { try map[hash(label)].append(Pair{ .value = v, .label = label, }); } } else { var m = &map[hash(label)]; for (m.items, 0..) |e, i| { if (mem.eql(u8, e.label, label)) { _ = m.orderedRemove(i); break; } } } } var ans: u64 = 0; for (map, 1..) |m, i| { for (m.items, 1..) |e, j| { ans += i * j * e.value; } } print("{d}\n", .{ans}); } pub fn solve(strings: []const []const u8) !void { part1(strings); try part2(strings); } pub fn main() !void { var splitComma = mem.splitScalar(u8, fin, ','); var strings = ArrayList([]const u8).init(allocator); while (splitComma.next()) |s| { try strings.append(s); } try solve(strings.items); }