diff --git a/12/input b/12/input new file mode 100644 index 0000000..84a1558 --- /dev/null +++ b/12/input @@ -0,0 +1,24 @@ +hl-WP +vl-fo +vl-WW +WP-start +vl-QW +fo-wy +WW-dz +dz-hl +fo-end +VH-fo +ps-vl +FN-dz +WP-ps +ps-start +WW-hl +end-QW +start-vl +WP-fo +end-FN +hl-QW +WP-dz +QW-fo +QW-dz +ps-dz \ No newline at end of file diff --git a/12/part1.zig b/12/part1.zig new file mode 100644 index 0000000..0bc5c20 --- /dev/null +++ b/12/part1.zig @@ -0,0 +1,130 @@ +const std = @import("std"); +const print = std.debug.print; + +const Node = []const u8; +const Route = std.ArrayList(Node); +const Edge = struct { + left: Node, + right: Node +}; + +fn contains(list: []Node, x: Node) bool { + for (list) |node| { + if (std.mem.eql(u8, node, x)) { + return true; + } + } + return false; +} + +fn getOther(edge: Edge, node: Node) ?Node { + if (std.mem.eql(u8, edge.left, node)) { + return edge.right; + } + if (std.mem.eql(u8, edge.right, node)) { + return edge.left; + } + return null; +} + +fn isSmol(node: Node) bool { + for (node) |rune| { + if (!std.ascii.isLower(rune)) return false; + } + + return true; +} + +pub fn main() !void { + var alloc = std.heap.GeneralPurposeAllocator(.{}){}; + defer std.debug.assert(!alloc.deinit()); + var gpa = &alloc.allocator; + + const stdin = std.io.getStdIn().reader(); + + var res: u32 = 0; + + var edges = std.ArrayList(Edge).init(gpa); + defer edges.deinit(); + + var input = try stdin.readAllAlloc(gpa, 4096); + defer gpa.free(input); + + var lines = std.mem.split(input, "\n"); + while (lines.next()) |line| { + var it = std.mem.split(line, "-"); + var left = it.next() orelse unreachable; + var right = it.next() orelse unreachable; + + try edges.append(Edge{ + .left = left, + .right = right, + }); + } + + var routes = std.ArrayList(Route).init(gpa); + defer { + for (routes.items) |route| { + route.deinit(); + } + routes.deinit(); + } + { + var route = Route.init(gpa); + try route.append("start"); + try routes.append(route); + } + + // var x: u8 = 0; + + while (true) { + var cont = false; + + var newRoutes = std.ArrayList(Route).init(gpa); + defer newRoutes.deinit(); + + var stale = std.ArrayList(usize).init(gpa); + defer stale.deinit(); + + // print("Routes ({}):\n", .{routes.items.len}); + // for (routes.items) |route| { + // print("{s}\n", .{route.items}); + // } + + for (routes.items) |route, i| { + const last = route.items[route.items.len - 1]; + if (std.mem.eql(u8, last, "end")) { + continue; + } + cont = true; + try stale.append(i); + + for (edges.items) |edge| { + if (getOther(edge, last)) |other| { + // print("> {s}\n", .{other}); + if (isSmol(other) and contains(route.items, other)) { + continue; + } else { + var newRoute = Route.init(gpa); + try newRoute.appendSlice(route.items); + try newRoute.append(other); + // print("new route: {s}\n", .{newRoute.items}); + try newRoutes.append(newRoute); + } + } + } + } + + var i: usize = 0; + while (i < stale.items.len) : (i += 1) { + var route = routes.orderedRemove(stale.items[stale.items.len-1-i]); + route.deinit(); + } + + try routes.appendSlice(newRoutes.items); + + if (!cont) break; + } + + std.debug.print("{}\n", .{routes.items.len}); +} diff --git a/12/part2.zig b/12/part2.zig new file mode 100644 index 0000000..f0573c7 --- /dev/null +++ b/12/part2.zig @@ -0,0 +1,169 @@ +const std = @import("std"); +const print = std.debug.print; + +const Node = u16; +const Route = []Node; +const Edge = struct { + left: Node, + right: Node +}; + +const START_NODE = 0x0000; +const END_NODE = 0xffff; + +fn parseNode(input: []const u8) Node { + if (std.mem.eql(u8, input, "start")) return START_NODE; + if (std.mem.eql(u8, input, "end")) return END_NODE; + if (input.len == 1) return @intCast(u16, input[0]) << 8 | 0x20; + return @intCast(u16, input[0]) << 8 | input[1]; +} + +fn isThereASmolDuplicate(list: []Node) bool { + for (list) |node| { + if (isSmol(node) and count(list, node) > 1) { + return true; + } + } + return false; +} + +fn count(list: []Node, x: Node) u32 { + var res: u32 = 0; + for (list) |node| { + if (node == x) { + res += 1; + if (res == 2) { + return 2; + } + } + } + return res; +} + +fn isForbiddenSmol(list: []Node, x: Node) bool { + if (isThereASmolDuplicate(list)) { + for (list) |node| { + if (node == x) { + return true; + } + } + return false; + } else if (x == START_NODE) { + return true; + } else { + return count(list, x) > 1; + } +} + +fn getOther(edge: Edge, node: Node) ?Node { + if (edge.left == node) { + return edge.right; + } + if (edge.right == node) { + return edge.left; + } + return null; +} + +fn isSmol(node: Node) bool { + return (node & 0x2020) == 0x2020 or node == START_NODE or node == END_NODE; +} + +pub fn main() !void { + var alloc = std.heap.GeneralPurposeAllocator(.{}){}; + defer std.debug.assert(!alloc.deinit()); + var gpa = &alloc.allocator; + + const stdin = std.io.getStdIn().reader(); + + var res: u32 = 0; + + var edges = std.ArrayList(Edge).init(gpa); + defer edges.deinit(); + + var input = try stdin.readAllAlloc(gpa, 4096); + defer gpa.free(input); + + var lines = std.mem.split(input, "\n"); + while (lines.next()) |line| { + var it = std.mem.split(line, "-"); + var left = it.next() orelse unreachable; + var right = it.next() orelse unreachable; + var leftInt = parseNode(left); + var rightInt = parseNode(right); + + try edges.append(Edge{ + .left = leftInt, + .right = rightInt, + }); + } + + var routes = std.ArrayList(Route).init(gpa); + defer { + for (routes.items) |route| { + gpa.free(route); + } + routes.deinit(); + } + { + var route = try gpa.alloc(Node, 1); + route[0] = START_NODE; + try routes.append(route); + } + + var x: u8 = 0; + + while (x < 1000) : (x += 1) { + var cont = false; + + var newRoutes = std.ArrayList(Route).init(gpa); + defer newRoutes.deinit(); + + var stale = std.ArrayList(usize).init(gpa); + defer stale.deinit(); + + // print("Routes ({}):\n", .{routes.items.len}); + // for (routes.items) |route| { + // print("{any}\n", .{route.items}); + // } + + for (routes.items) |route, i| { + const last = route[route.len - 1]; + if (last == END_NODE) { + continue; + } + cont = true; + try stale.append(i); + + for (edges.items) |edge| { + if (getOther(edge, last)) |other| { + // print("> {s}\n", .{other}); + if (isSmol(other) and isForbiddenSmol(route, other)) { + continue; + } else { + var newRoute = try gpa.alloc(Node, route.len+1); + std.mem.copy(Node, newRoute, route); + newRoute[route.len] = other; + // print("new route: {s}\n", .{newRoute.items}); + try newRoutes.append(newRoute); + } + } + } + } + + // print("Removed routes: {}\n", .{stale.items.len}); + // print("Added routes: {}\n", .{newRoutes.items.len}); + + var i: usize = 0; + while (i < stale.items.len) : (i += 1) { + var route = routes.swapRemove(stale.items[stale.items.len-1-i]); + gpa.free(route); + } + + try routes.appendSlice(newRoutes.items); + + if (!cont) break; + } + + std.debug.print("{}\n", .{routes.items.len}); +} diff --git a/12/testinput b/12/testinput new file mode 100644 index 0000000..898cd56 --- /dev/null +++ b/12/testinput @@ -0,0 +1,7 @@ +start-A +start-b +A-c +A-b +b-d +A-end +b-end \ No newline at end of file