const std = @import("std"); const Error = error{IndexError}; const T = u16; const S = 16; fn takeBlock(reader: *std.io.Reader) ![]u8 { const line = try reader.peekDelimiterExclusive('\n'); if (std.mem.indexOfScalar(u8, line, ' ')) |len| { reader.toss(len + 1); return line[0..len]; } else { reader.toss(line.len + 1); return line; } } fn nth(t: type, n: usize) t { return @as(t, 1) << @intCast(n); } fn parseIndicator(s: []u8) T { var value: T = 0; for (s[1..s.len - 1], 0..) |c, i| { if (c == '#') { value |= nth(T, i); } } return value; } fn parseButton(s: []u8) !T { var i: usize = 1; var button: T = 0; while (std.mem.indexOfScalar(u8, s[i..], ',')) |j| { const v = try std.fmt.parseInt(usize, s[i..i+j], 10); button |= nth(T, v); i += j + 1; } else { const v = try std.fmt.parseInt(usize, s[i..s.len-1], 10); button |= nth(T, v); } return button; } fn increment(stack: *[S]usize, i: usize, n: usize) bool { if (stack[i] + 1 < n) { stack[i] += 1; return false; } else if (i > 0) { const inc = increment(stack, i - 1, n - 1); stack[i] = stack[i - 1] + 1; return inc; } else { stack[i] = 0; return true; } } fn foo(target: T, buttons: []T) usize { var count: usize = 1; var stack = [_]usize{0} ** S; std.debug.assert(buttons.len <= stack.len); while (count <= buttons.len) { var v: T = 0; for (0..count) |i| { v ^= buttons[stack[i]]; } if (v == target) { return count; } if (increment(&stack, count - 1, buttons.len)) { stack[count] = stack[count - 1] + 1; count += 1; } } unreachable; } pub fn main() !void { const allocator = std.heap.smp_allocator; const path: [:0]const u8 = std.mem.span(std.os.argv[1]); var file = try std.fs.cwd().openFile(path, .{}); defer file.close(); var buffer: [1024]u8 = undefined; var reader = file.reader(&buffer); var part1: usize = 0; var target: T = 0; var buttons = std.ArrayList(T).empty; defer buttons.deinit(allocator); while (takeBlock(&reader.interface)) |s| { if (s[0] == '[') { target = parseIndicator(s); buttons.clearRetainingCapacity(); } else if (s[0] == '(') { try buttons.append(allocator, try parseButton(s)); } else { const count = foo(target, buttons.items); part1 += count; } } else |err| switch (err) { error.EndOfStream => {}, else => |e| return e, } std.debug.print("part1: {}\n", .{part1}); }