advent-of-code-2021/12/part2.zig

170 lines
4.3 KiB
Zig
Raw Normal View History

2021-12-17 17:57:32 +00:00
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});
}