const std = @import("std"); pub const title = "Day 11: Reactor"; pub fn run(allocator: std.mem.Allocator) !void { const input = @embedFile("./input/day11.txt"); //const input = // \\aaa: you hhh // \\you: bbb ccc // \\bbb: ddd eee // \\ccc: ddd eee fff // \\ddd: ggg // \\eee: out // \\fff: out // \\ggg: out // \\hhh: ccc fff iii // \\iii: out // ; //const input = // \\svr: aaa bbb // \\aaa: fft // \\fft: ccc // \\bbb: tty // \\tty: ccc // \\ccc: ddd eee // \\ddd: hub // \\hub: fff // \\eee: dac // \\dac: fff // \\fff: ggg hhh // \\ggg: out // \\hhh: out // ; var lines = std.mem.tokenizeScalar(u8, input, '\n'); var devices: std.StringHashMap([][]const u8) = .init(allocator); defer { var outputs_iter = devices.valueIterator(); while (outputs_iter.next()) |value| { allocator.free(value.*); } devices.deinit(); } while (lines.next()) |line| { const device = line[0..3]; std.debug.print("device = {s}\n", .{device}); var outputs: std.ArrayList([]const u8) = .empty; defer outputs.deinit(allocator); var outputs_iter = std.mem.tokenizeScalar(u8, line[5..], ' '); while (outputs_iter.next()) |output| { try outputs.append(allocator, output); } const outputs_slice = try outputs.toOwnedSlice(allocator); errdefer allocator.free(outputs_slice); try devices.put(device, outputs_slice); } var cache: std.StringHashMap(usize) = .init(allocator); defer cache.deinit(); try cache.ensureTotalCapacity(devices.count()); const dac_to_fft = try visitOutputs("dac", "fft", devices, &cache); const svr_to_fft = try visitOutputs("svr", "fft", devices, &cache); cache.clearRetainingCapacity(); const to_fft = if (dac_to_fft == 0) svr_to_fft else dac_to_fft; const dac_start = if (dac_to_fft == 0) "fft" else "svr"; const end_start = if (dac_to_fft == 0) "dac" else "fft"; const to_dac = try visitOutputs(dac_start, "dac", devices, &cache); cache.clearRetainingCapacity(); const to_end = try visitOutputs(end_start, "out", devices, &cache); const result = to_fft * to_dac * to_end; var buffer: [8]u8 = undefined; var stdout_writer = std.fs.File.stdout().writer(&buffer); const stdout = &stdout_writer.interface; try stdout.print("{d}\n", .{result}); try stdout.flush(); } fn visitOutputs( start: []const u8, end: []const u8, devices: std.StringHashMap([][]const u8), cache: *std.StringHashMap(usize), ) !usize { if (cache.get(start)) |result| { return result; } var paths: usize = 0; const device = devices.get(start); if (device) |outputs| { for (outputs) |output| { if (std.mem.eql(u8, output, end)) { paths += 1; } else { paths += try visitOutputs(output, end, devices, cache); } } try cache.put(start, paths); return paths; } else { std.debug.print("device {s} not found\n", .{start}); return 0; } }