diff --git a/src/day14.zig b/src/day14.zig index 808eec6..29e96a6 100644 --- a/src/day14.zig +++ b/src/day14.zig @@ -2,7 +2,6 @@ const std = @import("std"); const aoc = @import("./aoc.zig"); const assert = std.debug.assert; const Allocator = std.mem.Allocator; -const PointU32 = @import("./point.zig").Point(u32); const Tile = enum { Empty, diff --git a/src/day15.zig b/src/day15.zig new file mode 100644 index 0000000..d05b25b --- /dev/null +++ b/src/day15.zig @@ -0,0 +1,159 @@ +const std = @import("std"); +const aoc = @import("./aoc.zig"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; + +const Input = struct { + parts: std.ArrayList([]const u8), + + fn init(allocator: Allocator) Input { + return Input{ + .parts = std.ArrayList([]const u8).init(allocator) + }; + } + + fn deinit(self: Input) void { + self.parts.deinit(); + } +}; + +const HashMapItem = struct { + key: []const u8, + value: u8 +}; + +const HashMap = struct { + boxes: [256]std.ArrayList(HashMapItem), + + fn init(allocator: Allocator) HashMap { + var boxes: [256]std.ArrayList(HashMapItem) = undefined; + for (0..256) |i| { + boxes[i] = std.ArrayList(HashMapItem).init(allocator); + } + + return HashMap{ .boxes = boxes }; + } + + fn deinit(self: HashMap) void { + for (self.boxes) |box| { + box.deinit(); + } + } + + fn put(self: *HashMap, key: []const u8, value: u8) !void { + const hash = compute_hash(key); + var box = &self.boxes[hash]; + + for (box.items) |*item| { + if (std.mem.eql(u8, item.key, key)) { + item.value = value; + return; + } + } + + try box.append(HashMapItem{ .key = key, .value = value }); + } + + fn remove(self: *HashMap, key: []const u8) void { + const hash = compute_hash(key); + var box = &self.boxes[hash]; + for (0.., box.items) |i, item| { + if (std.mem.eql(u8, item.key, key)) { + _ = box.orderedRemove(i); + break; + } + } + } + + fn debug(self: HashMap) void { + for (0.., self.boxes) |i, box| { + if (box.items.len == 0) continue; + + std.debug.print("Box {}:", .{i}); + for (box.items) |item| { + std.debug.print(" [{s} {}]", .{item.key, item.value}); + } + std.debug.print("\n", .{}); + } + } +}; + +fn parse_input(allocator: Allocator, lines: []const []const u8) !Input { + var result = Input.init(allocator); + errdefer result.deinit(); + + var iter = std.mem.splitScalar(u8, lines[0], ','); + while (iter.next()) |part| { + try result.parts.append(part); + } + + return result; +} + +fn compute_hash(text: []const u8) u8 { + var current: u16 = 0; + for (text) |symbol| { + current += symbol; + current *= 17; + current %= 256; + } + return @intCast(current); +} + +pub fn part1(input: *aoc.Input) !aoc.Result { + const parsed = try parse_input(input.allocator, input.lines); + defer parsed.deinit(); + + var result: u64 = 0; + for (parsed.parts.items) |item| { + result += compute_hash(item); + } + + return .{ .uint = result }; +} + +pub fn part2(input: *aoc.Input) !aoc.Result { + const allocator = input.allocator; + const parsed = try parse_input(input.allocator, input.lines); + defer parsed.deinit(); + + var hash_map = HashMap.init(allocator); + defer hash_map.deinit(); + + for (parsed.parts.items) |inst| { + if (inst[inst.len - 1] == '-') { + const key = inst[0..(inst.len-1)]; + hash_map.remove(key); + } else { + const equal_pos = std.mem.indexOfScalar(u8, inst, '=') orelse return error.InvalidInstruction; + const key = inst[0..equal_pos]; + const value = inst[(equal_pos+1)] - '0'; + try hash_map.put(key, value); + } + + // std.debug.print("After \"{s}\":\n", .{inst}); + // hash_map.debug(); + // std.debug.print("\n", .{}); + } + + var result: u64 = 0; + for (1.., hash_map.boxes) |box_idx, box| { + for (1.., box.items) |item_idx, item| { + result += box_idx * item_idx * item.value; + } + } + + return .{ .uint = result }; +} + +const example_input = [_][]const u8{ + "rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7" +}; + +test "part 1 example" { + try aoc.expectAnswerUInt(part1, 1320, &example_input); +} + +test "part 2 example" { + try aoc.expectAnswerUInt(part2, 145, &example_input); +} diff --git a/src/main.zig b/src/main.zig index e35e139..07299b4 100644 --- a/src/main.zig +++ b/src/main.zig @@ -35,6 +35,7 @@ const Days = [_]aoc.Day{ create_day(@import("./day12.zig")), create_day(@import("./day13.zig")), create_day(@import("./day14.zig")), + create_day(@import("./day15.zig")), }; fn kilobytes(count: u32) u32 { @@ -73,10 +74,8 @@ fn run(allocator: Allocator, args: *cli) !u8 { lines.deinit(); } - var line_buf: [1024]u8 = undefined; - while (try reader.readUntilDelimiterOrEof(&line_buf, '\n')) |line| { - var trimmed_line = std.mem.trimRight(u8, line, &.{'\r'}); - try lines.append(try allocator.dupe(u8, trimmed_line)); + while (try reader.readUntilDelimiterOrEofAlloc(allocator, '\n', kilobytes(32))) |line| { + try lines.append(std.mem.trimRight(u8, line, &.{'\r'})); } var input = aoc.Input{ .allocator = allocator, .lines = lines.items }; @@ -193,4 +192,5 @@ test { _ = @import("./day12.zig"); _ = @import("./day13.zig"); _ = @import("./day14.zig"); + _ = @import("./day15.zig"); }