1use std::array;
2use utils::prelude::*;
3
4#[derive(Clone, Debug)]
6pub struct Day15 {
7 part1: i32,
8 part2: i32,
9}
10
11impl Day15 {
12 pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
13 let ingredients = parser::i32()
14 .with_prefix(": capacity ")
15 .with_prefix(parser::take_while1(u8::is_ascii_alphabetic))
16 .then(parser::i32().with_prefix(", durability "))
17 .then(parser::i32().with_prefix(", flavor "))
18 .then(parser::i32().with_prefix(", texture "))
19 .then(parser::i32().with_prefix(", calories "))
20 .map(|(a, b, c, d, e)| [a, b, c, d, e])
21 .parse_lines(input)?;
22
23 let (part1, part2) = Self::ingredients(100, [0; 5], &ingredients);
24 Ok(Self { part1, part2 })
25 }
26
27 fn ingredients(teaspoons: i32, totals: [i32; 5], ingredients: &[[i32; 5]]) -> (i32, i32) {
28 if let Ok(two_ingredients) = ingredients.try_into() {
29 return Self::two_ingredients(teaspoons, totals, two_ingredients);
30 }
31
32 let (ingredient, remaining) = ingredients.split_first().unwrap();
33 (0..=teaspoons)
34 .map(|t| {
35 Self::ingredients(
36 teaspoons - t,
37 array::from_fn(|i| totals[i] + t * ingredient[i]),
38 remaining,
39 )
40 })
41 .fold((0, 0), |(a1, b1), (a2, b2)| (a1.max(a2), b1.max(b2)))
42 }
43
44 fn two_ingredients(teaspoons: i32, totals: [i32; 5], ingredients: [[i32; 5]; 2]) -> (i32, i32) {
45 if (0..5).any(|i| totals[i] <= 0 && ingredients[0][i] <= 0 && ingredients[1][i] <= 0) {
48 return (0, 0);
49 }
50
51 (0..=teaspoons)
52 .map(|t| {
53 let totals: [i32; 5] = array::from_fn(|i| {
54 totals[i] + (t * ingredients[0][i]) + ((teaspoons - t) * ingredients[1][i])
55 });
56
57 if totals[0] <= 0 || totals[1] <= 0 || totals[2] <= 0 || totals[3] <= 0 {
58 (0, 0)
59 } else {
60 let score = totals[0] * totals[1] * totals[2] * totals[3];
61 (score, if totals[4] == 500 { score } else { 0 })
62 }
63 })
64 .fold((0, 0), |(a1, b1), (a2, b2)| (a1.max(a2), b1.max(b2)))
65 }
66
67 #[must_use]
68 pub fn part1(&self) -> i32 {
69 self.part1
70 }
71
72 #[must_use]
73 pub fn part2(&self) -> i32 {
74 self.part2
75 }
76}
77
78examples!(Day15 -> (i32, i32) [
79 {
80 input: "Butterscotch: capacity -1, durability -2, flavor 6, texture 3, calories 8\n\
81 Cinnamon: capacity 2, durability 3, flavor -2, texture -1, calories 3",
82 part1: 62842880,
83 part2: 57600000,
84 },
85]);