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