// tedious and bad code but zig is mostly fine ig const std = @import("std"); var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); const alloc = arena.allocator(); const test_data = @embedFile("test"); const input_data = @embedFile("input"); pub fn main() !void { const stdout = std.io.getStdOut().writer(); const value1 = try run1(input_data); try stdout.print("{d}\n", .{value1}); const value2 = try run2(input_data); try stdout.print("{d}\n", .{value2}); } test "test input part 1" { std.debug.print("\n", .{}); const value = try run1(test_data); std.debug.print("{d}\n", .{value}); try std.testing.expectEqual(3749, value); } test "test input part 2" { std.debug.print("\n",.{}); const value = try run2(test_data); std.debug.print("{d}\n", .{value}); try std.testing.expectEqual(11387, value); } fn parseIntFromReader(reader: anytype) anyerror!u64 { const f = try reader.readByte(); if (f < '0' or f > '9') return error.BadCharacter; var v: u64 = f - '0'; while (true) { const c = try reader.readByte(); if (c < '0' or c > '9') { break; } else { v = (v * 10) + (c - '0'); } } return v; } fn run2(s: []const u8) !u64 { var total: u64 = 0; const Entry = struct { n: u64, nums: std.ArrayList(u64) }; var entries = std.ArrayList(Entry).init(alloc); var s_fbs = std.io.fixedBufferStream(s); var s_reader = s_fbs.reader(); l: while (true) { const err: anyerror!void = b: { const n = parseIntFromReader(s_reader) catch |e| break :b e; try s_fbs.seekBy(-1); if ((s_reader.readByte() catch |e| break :b e) != ':') break :b error.BadCharacter; var e: Entry = Entry { .n = n, .nums = std.ArrayList(u64).init(alloc) }; while ((s_reader.readByte() catch |er| break :b er) != '\n') { const i = parseIntFromReader(s_reader) catch |er| break :b er; try s_fbs.seekBy(-1); try e.nums.append(i); } try entries.append(e); }; _ = err catch |e| switch (e) { error.EndOfStream => { break :l; }, else => return e }; } var str_buf: [64]u8 = undefined; var str_buf_fbs = std.io.fixedBufferStream(&str_buf); var str_buf_writer = str_buf_fbs.writer(); for (entries.items) |entry| { const nums: []u64 = entry.nums.items; std.debug.print("{}:", .{entry.n}); for (nums) |i| { std.debug.print(" {}", .{i}); } std.debug.print("\n",.{}); const OP = enum { ADD, MUL, CAT }; var ops: [32]OP = .{OP.ADD}**32; check: while (true) { var op_i: usize = 0; var v = nums[0]; for (nums[1..]) |n| { switch (ops[op_i]) { OP.ADD => v += n, OP.MUL => v *= n, OP.CAT => { try str_buf_fbs.seekTo(0); try std.fmt.formatInt(v, 10, std.fmt.Case.lower, .{}, &str_buf_writer); try std.fmt.formatInt(n, 10, std.fmt.Case.lower, .{}, &str_buf_writer); v = try std.fmt.parseInt(u64, str_buf[0..str_buf_fbs.pos], 10); }, } op_i += 1; } if (v == entry.n) { std.debug.print("good!\n",.{}); total += entry.n; break :check; } var i: usize = 0; while (true) { switch(ops[i]) { OP.ADD => ops[i] = OP.MUL, OP.MUL => ops[i] = OP.CAT, OP.CAT => { ops[i] = OP.ADD; i += 1; continue; } } if (i >= nums.len - 1) break :check; break; } } } total += 0; return total; } fn run1(s: []const u8) !u64 { var total: u64 = 0; const Entry = struct { n: u64, nums: std.ArrayList(u64) }; var entries = std.ArrayList(Entry).init(alloc); var s_fbs = std.io.fixedBufferStream(s); var s_reader = s_fbs.reader(); l: while (true) { const err: anyerror!void = b: { const n = parseIntFromReader(s_reader) catch |e| break :b e; try s_fbs.seekBy(-1); if ((s_reader.readByte() catch |e| break :b e) != ':') break :b error.BadCharacter; var e: Entry = Entry { .n = n, .nums = std.ArrayList(u64).init(alloc) }; while ((s_reader.readByte() catch |er| break :b er) != '\n') { const i = parseIntFromReader(s_reader) catch |er| break :b er; try s_fbs.seekBy(-1); try e.nums.append(i); } try entries.append(e); }; _ = err catch |e| switch (e) { error.EndOfStream => { break :l; }, else => return e }; } for (entries.items) |entry| { const nums: []u64 = entry.nums.items; std.debug.print("{}:", .{entry.n}); for (nums) |i| { std.debug.print(" {}", .{i}); } std.debug.print("\n",.{}); var ops: u32 = 0; const op_mask = (@as(u32,1) << @intCast(nums.len - 1)) - 1; check: while (true) { var no = ops; var v = nums[0]; for (nums[1..]) |n| { if (no & 1 == 1) { v *= n; } else { v += n; } no >>= 1; } if (v == entry.n) { std.debug.print("good!\n",.{}); total += entry.n; break :check; } ops += 1; if (ops & op_mask == 0) { break :check; } } } total += 0; return total; }