summaryrefslogtreecommitdiff
path: root/day_07.zig
diff options
context:
space:
mode:
authorChristian Segundo2022-12-07 16:37:04 +0100
committerChristian Segundo2022-12-07 21:25:49 +0100
commit4ebc66911da17b6f5abdc7629dff3eccd7f37ce2 (patch)
tree74174c63a8df0510057d69a5195c050f6a56df68 /day_07.zig
parenta0d86708c88050deeee31f48e79115b38d5ebb56 (diff)
downloadadvent-of-zig-2022-4ebc66911da17b6f5abdc7629dff3eccd7f37ce2.tar.gz
add day 7
Diffstat (limited to 'day_07.zig')
-rw-r--r--day_07.zig129
1 files changed, 129 insertions, 0 deletions
diff --git a/day_07.zig b/day_07.zig
new file mode 100644
index 0000000..01c71a2
--- /dev/null
+++ b/day_07.zig
@@ -0,0 +1,129 @@
+const std = @import("std");
+const Result = @import("util/aoc.zig").Result;
+
+const NodeType = union(enum) { File, Dir };
+const Node = struct {
+ Name: []const u8,
+ Childs: struct {
+ len: usize = 0,
+ items: [300]?*Node = [_]?*Node{null} ** 300,
+ } = .{},
+ Parent: ?*Node = null,
+ Type: NodeType,
+ Size: usize = 0,
+
+ pub fn append(self: *Node, node: *Node) void {
+ self.Childs.items[self.Childs.len] = node;
+ self.Childs.len += 1;
+ }
+
+ fn cd(self: *Node, to: []const u8) *Node {
+ if (to.len == 1 and to[0] == '/') {
+ if (self.Parent == null) return self;
+ return self.Parent.?.cd("/");
+ }
+
+ if (std.mem.eql(u8, "..", to)) {
+ return self.Parent.?;
+ }
+
+ for (self.Childs.items[0..self.Childs.len]) |child| {
+ if (std.mem.eql(u8, child.?.Name, to)) return child.?;
+ }
+
+ unreachable;
+ }
+
+ fn size(self: Node) usize {
+ if (self.Type == .File) return self.Size;
+ var s: usize = 0;
+ for (self.Childs.items[0..self.Childs.len]) |child| s += child.?.size();
+ return s;
+ }
+};
+
+fn compute_puzzle_1(node: Node) usize {
+ var size: usize = 0;
+ for (node.Childs.items[0..node.Childs.len]) |child| {
+ if (child.?.Type != NodeType.Dir) continue;
+ if (child.?.size() <= 100000) size += child.?.size();
+ size += compute_puzzle_1(child.?.*);
+ }
+ return size;
+}
+
+fn compute_puzzle_2(node: Node, min: usize, target: usize) usize {
+ var new_min = min;
+ for (node.Childs.items[0..node.Childs.len]) |child| {
+ if (child.?.Type != NodeType.Dir) continue;
+ const child_size = child.?.size();
+ if (child_size < new_min and child_size >= target) new_min = child_size;
+ new_min = compute_puzzle_2(child.?.*, new_min, target);
+ }
+ return new_min;
+}
+
+fn build_tree(allocator: std.mem.Allocator, root: *Node, input: []const u8) !void {
+ var iter = std.mem.split(u8, input, "\n");
+
+ var current_root = &root;
+
+ while (iter.next()) |line| {
+ if (line[0] == '$') {
+ if (std.mem.eql(u8, line[2..4], "cd")) current_root = &current_root.*.cd(line[5..]);
+ continue;
+ }
+
+ var node = try allocator.create(Node);
+ node.* = .{
+ .Name = line[std.mem.indexOf(u8, line, " ").? + 1 ..],
+ .Parent = current_root.*,
+ .Type = blk: {
+ if (std.mem.eql(u8, line[0..3], "dir")) break :blk NodeType.Dir;
+ break :blk NodeType.File;
+ },
+ .Size = blk: {
+ break :blk std.fmt.parseInt(
+ usize,
+ line[0..std.mem.indexOf(u8, line, " ").?],
+ 0,
+ ) catch 0;
+ },
+ };
+ current_root.*.append(node);
+ }
+}
+
+pub fn puzzle_1(allocator: std.mem.Allocator, input: []const u8) Result {
+ var arena = std.heap.ArenaAllocator.init(allocator);
+ defer arena.deinit();
+
+ var node = Node{
+ .Name = "/",
+ .Type = .Dir,
+ };
+
+ build_tree(arena.allocator(), &node, input) catch unreachable;
+
+ return .{ .int = @intCast(i32, compute_puzzle_1(node)) };
+}
+
+pub fn puzzle_2(allocator: std.mem.Allocator, input: []const u8) Result {
+ var arena = std.heap.ArenaAllocator.init(allocator);
+ defer arena.deinit();
+
+ var node = Node{
+ .Name = "/",
+ .Type = .Dir,
+ };
+
+ build_tree(arena.allocator(), &node, input) catch unreachable;
+
+ const target: usize = 30000000 - (70000000 - node.size());
+
+ return .{ .int = @intCast(i32, compute_puzzle_2(
+ node,
+ node.size(),
+ target,
+ )) };
+}