const std = @import("std"); const PATH = "input/day15.txt"; const Str = []const u8; const TEASPOON = 100; pub fn first(allocator: std.mem.Allocator) !usize { const ings = try parseInput(allocator, @embedFile(PATH)); defer allocator.free(ings); var max: usize = 0; var p: isize = 1; while (p < TEASPOON) : (p += 1) { var q: isize = 1; while (q < TEASPOON - p) : (q += 1) { var r: isize = 1; while (r < TEASPOON - p - q) : (r += 1) { var s: isize = 1; while (s < TEASPOON - p - q - r + 1) : (s += 1) { if (p + q + r + s != 100) continue; const capacity = std.math.max(0, ings[0].capacity * p + ings[1].capacity * q + ings[2].capacity * r + ings[3].capacity * s); if (capacity == 0) continue; const durability = std.math.max(0, ings[0].durability * p + ings[1].durability * q + ings[2].durability * r + ings[3].durability * s); if (durability == 0) continue; const flavor = std.math.max(0, ings[0].flavor * p + ings[1].flavor * q + ings[2].flavor * r + ings[3].flavor * s); if (flavor == 0) continue; const texture = std.math.max(0, ings[0].texture * p + ings[1].texture * q + ings[2].texture * r + ings[3].texture * s); if (texture == 0) continue; const val = capacity * durability * flavor * texture; if (val > max) max = @intCast(usize, val); } } } } return max; } pub fn second(allocator: std.mem.Allocator) !usize { const TARGET_CALORIES = 500; const ings = try parseInput(allocator, @embedFile(PATH)); defer allocator.free(ings); var max: usize = 0; var p: isize = 1; while (p < TEASPOON) : (p += 1) { var q: isize = 1; while (q < TEASPOON - p) : (q += 1) { var r: isize = 1; while (r < TEASPOON - p - q) : (r += 1) { var s: isize = 1; while (s < TEASPOON - p - q - r + 1) : (s += 1) { if (p + q + r + s != 100) continue; const calories = ings[0].calories * p + ings[1].calories * q + ings[2].calories * r + ings[3].calories * s; if (calories != TARGET_CALORIES) continue; const capacity = std.math.max(0, ings[0].capacity * p + ings[1].capacity * q + ings[2].capacity * r + ings[3].capacity * s); if (capacity == 0) continue; const durability = std.math.max(0, ings[0].durability * p + ings[1].durability * q + ings[2].durability * r + ings[3].durability * s); if (durability == 0) continue; const flavor = std.math.max(0, ings[0].flavor * p + ings[1].flavor * q + ings[2].flavor * r + ings[3].flavor * s); if (flavor == 0) continue; const texture = std.math.max(0, ings[0].texture * p + ings[1].texture * q + ings[2].texture * r + ings[3].texture * s); if (texture == 0) continue; const val = capacity * durability * flavor * texture; if (val > max) max = @intCast(usize, val); } } } } return max; } test "day15a" { try std.testing.expectEqual(@as(usize, 222870), try first(std.testing.allocator)); } test "day15b" { try std.testing.expectEqual(@as(usize, 117936), try second(std.testing.allocator)); } const Ingredient = struct { capacity: isize, durability: isize, flavor: isize, texture: isize, calories: isize, }; fn parseInput(allocator: std.mem.Allocator, input: Str) ![]Ingredient { var ingredients = std.ArrayList(Ingredient).init(allocator); defer ingredients.deinit(); var lines = std.mem.tokenize(u8, input, "\n"); while (lines.next()) |line| { var name_prop = std.mem.tokenize(u8, line, ":"); _ = name_prop.next(); // drop name var props = std.mem.tokenize(u8, name_prop.next().?, ","); var ingr: Ingredient = undefined; var counter: usize = 0; while (props.next()) |prop| { var name_val = std.mem.tokenize(u8, prop, " "); _ = name_val.next(); const val = try std.fmt.parseInt(isize, name_val.next().?, 10); switch (counter) { 0 => ingr.capacity = val, 1 => ingr.durability = val, 2 => ingr.flavor = val, 3 => ingr.texture = val, 4 => ingr.calories = val, else => unreachable, } counter += 1; } try ingredients.append(ingr); } return try ingredients.toOwnedSlice(); }