1use crate::util::iter::*;
6use crate::util::parse::*;
7use std::ops::Add;
8
9#[derive(Clone, Copy)]
10struct Item {
11 cost: i32,
12 damage: i32,
13 armor: i32,
14}
15
16impl Add for Item {
17 type Output = Self;
18
19 fn add(self, rhs: Self) -> Self {
20 Item {
21 cost: self.cost + rhs.cost,
22 damage: self.damage + rhs.damage,
23 armor: self.armor + rhs.armor,
24 }
25 }
26}
27
28type Result = (bool, i32);
29
30pub fn parse(input: &str) -> Vec<Result> {
31 let [boss_health, boss_damage, boss_armor]: [i32; 3] =
32 input.iter_signed().chunk::<3>().next().unwrap();
33
34 let weapon = [
35 Item { cost: 8, damage: 4, armor: 0 },
36 Item { cost: 10, damage: 5, armor: 0 },
37 Item { cost: 25, damage: 6, armor: 0 },
38 Item { cost: 40, damage: 7, armor: 0 },
39 Item { cost: 74, damage: 8, armor: 0 },
40 ];
41
42 let armor = [
43 Item { cost: 0, damage: 0, armor: 0 },
44 Item { cost: 13, damage: 0, armor: 1 },
45 Item { cost: 31, damage: 0, armor: 2 },
46 Item { cost: 53, damage: 0, armor: 3 },
47 Item { cost: 75, damage: 0, armor: 4 },
48 Item { cost: 102, damage: 0, armor: 5 },
49 ];
50
51 let ring = [
52 Item { cost: 25, damage: 1, armor: 0 },
53 Item { cost: 50, damage: 2, armor: 0 },
54 Item { cost: 100, damage: 3, armor: 0 },
55 Item { cost: 20, damage: 0, armor: 1 },
56 Item { cost: 40, damage: 0, armor: 2 },
57 Item { cost: 80, damage: 0, armor: 3 },
58 ];
59
60 let mut combinations = Vec::with_capacity(22);
61 combinations.push(Item { cost: 0, damage: 0, armor: 0 });
62
63 for i in 0..6 {
64 combinations.push(ring[i]);
65 for j in (i + 1)..6 {
66 combinations.push(ring[i] + ring[j]);
67 }
68 }
69
70 let mut results = Vec::with_capacity(660);
71
72 for first in weapon {
73 for second in armor {
74 for &third in &combinations {
75 let Item { cost, damage, armor } = first + second + third;
76
77 let hero_turns = boss_health / (damage - boss_armor).max(1);
78 let boss_turns = 100 / (boss_damage - armor).max(1);
79 let win = hero_turns <= boss_turns;
80
81 results.push((win, cost));
82 }
83 }
84 }
85
86 results
87}
88
89pub fn part1(input: &[Result]) -> i32 {
90 *input.iter().filter_map(|(w, c)| w.then_some(c)).min().unwrap()
91}
92
93pub fn part2(input: &[Result]) -> i32 {
94 *input.iter().filter_map(|(w, c)| (!w).then_some(c)).max().unwrap()
95}