diff options
author | Mathias Magnusson <mathias@magnusson.space> | 2024-12-07 14:47:55 +0100 |
---|---|---|
committer | Mathias Magnusson <mathias@magnusson.space> | 2024-12-07 14:47:55 +0100 |
commit | f3d2506b162f5d4c432e393ee9c24cca566cbc80 (patch) | |
tree | 8fbdfa523ba2ac968422a9e560d2672c060e4e16 | |
parent | a7413db41b2b597744d512b6be95a14fc1b70243 (diff) | |
download | programming-problem-solving-f3d2506b162f5d4c432e393ee9c24cca566cbc80.tar.gz |
aoc2024: day 7
-rw-r--r-- | aoc24/src/day7.zig | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/aoc24/src/day7.zig b/aoc24/src/day7.zig new file mode 100644 index 0000000..912eac1 --- /dev/null +++ b/aoc24/src/day7.zig @@ -0,0 +1,101 @@ +const std = @import("std"); + +const Equation = struct { total: u64, numbers: []u64 }; + +const Input = []Equation; + +pub fn parse(allocator: std.mem.Allocator, data: []const u8) !Input { + var lines = std.mem.split(u8, data, "\n"); + var equations = std.ArrayList(Equation).init(allocator); + while (lines.next()) |line| { + if (line.len == 0) continue; + var split = std.mem.split(u8, line, " "); + const total = try std.fmt.parseInt( + u64, + std.mem.trimRight(u8, split.next() orelse return error.InvalidInput, ":"), + 10, + ); + var numbers = std.ArrayList(u64).init(allocator); + while (split.next()) |number| { + try numbers.append(try std.fmt.parseInt(u64, number, 10)); + } + try equations.append(.{ .total = total, .numbers = numbers.items }); + } + return equations.items; +} + +const test_input = + \\190: 10 19 + \\3267: 81 40 27 + \\83: 17 5 + \\156: 15 6 + \\7290: 6 8 6 15 + \\161011: 16 10 13 + \\192: 17 8 14 + \\21037: 9 7 18 13 + \\292: 11 6 16 20 + \\ +; + +test "part1" { + var arena = std.heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + + const output = try part1(arena.allocator(), try parse(arena.allocator(), test_input)); + std.debug.print("got {}\n", .{output}); + std.debug.assert(output == 3749); +} + +fn can_become(total: u64, numbers: []u64, target: u64) bool { + // std.debug.print("can_become({}, {any}, {})\n", .{ total, numbers, target }); + if (numbers.len == 0) return total == target; + const last = numbers.len - 1; + return total >= numbers[last] and can_become(total - numbers[last], numbers[0..last], 0) or + total % numbers[last] == 0 and can_become(total / numbers[last], numbers[0..last], 1); +} + +pub fn part1(_: std.mem.Allocator, input: Input) !u64 { + var sum: u64 = 0; + for (input) |equation| { + if (can_become(equation.total, equation.numbers, 0)) + sum += equation.total; + // std.debug.print("\n", .{}); + } + + return sum; +} + +test "part2" { + var arena = std.heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + + const output = try part2(arena.allocator(), try parse(arena.allocator(), test_input)); + std.debug.print("got {}\n", .{output}); + std.debug.assert(output == 11387); +} + +fn can_become2(total: u64, numbers: []u64, target: u64) bool { + // std.debug.print("can_become({}, {any}, {})\n", .{ total, numbers, target }); + if (numbers.len == 0) return total == target; + const last = numbers.len - 1; + // Addition + return (total >= numbers[last] and can_become2(total - numbers[last], numbers[0..last], 0)) or + // Multiplication + (total % numbers[last] == 0 and can_become2(total / numbers[last], numbers[0..last], 1)) or blk: { + // Concatenation + const digit_count = std.fmt.count("{}", .{numbers[last]}); + const concat_mult = std.math.pow(u64, 10, digit_count); + break :blk (total >= numbers[last] and (total - numbers[last]) % concat_mult == 0 and can_become2((total - numbers[last]) / concat_mult, numbers[0..last], 0)); + }; +} + +pub fn part2(_: std.mem.Allocator, input: Input) !u64 { + var sum: u64 = 0; + for (input) |equation| { + if (can_become2(equation.total, equation.numbers, 0)) + sum += equation.total; + // std.debug.print("\n", .{}); + } + + return sum; +} |