-
Notifications
You must be signed in to change notification settings - Fork 4
/
day21.rs
95 lines (78 loc) · 2.63 KB
/
day21.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//! # RPG Simulator 20XX
//!
//! The trick to get the outcome of each battle quickly is to divide the hero's health by the
//! boss's damage and vice-versa then find out how many turns each takes to win.
use crate::util::iter::*;
use crate::util::parse::*;
use std::ops::Add;
#[derive(Clone, Copy)]
struct Item {
cost: i32,
damage: i32,
armor: i32,
}
impl Add for Item {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Item {
cost: self.cost + rhs.cost,
damage: self.damage + rhs.damage,
armor: self.armor + rhs.armor,
}
}
}
type Result = (bool, i32);
pub fn parse(input: &str) -> Vec<Result> {
let [boss_health, boss_damage, boss_armor]: [i32; 3] =
input.iter_signed().chunk::<3>().next().unwrap();
let weapon = [
Item { cost: 8, damage: 4, armor: 0 },
Item { cost: 10, damage: 5, armor: 0 },
Item { cost: 25, damage: 6, armor: 0 },
Item { cost: 40, damage: 7, armor: 0 },
Item { cost: 74, damage: 8, armor: 0 },
];
let armor = [
Item { cost: 0, damage: 0, armor: 0 },
Item { cost: 13, damage: 0, armor: 1 },
Item { cost: 31, damage: 0, armor: 2 },
Item { cost: 53, damage: 0, armor: 3 },
Item { cost: 75, damage: 0, armor: 4 },
Item { cost: 102, damage: 0, armor: 5 },
];
let ring = [
Item { cost: 25, damage: 1, armor: 0 },
Item { cost: 50, damage: 2, armor: 0 },
Item { cost: 100, damage: 3, armor: 0 },
Item { cost: 20, damage: 0, armor: 1 },
Item { cost: 40, damage: 0, armor: 2 },
Item { cost: 80, damage: 0, armor: 3 },
];
let mut combinations = Vec::with_capacity(22);
combinations.push(Item { cost: 0, damage: 0, armor: 0 });
for i in 0..6 {
combinations.push(ring[i]);
for j in (i + 1)..6 {
combinations.push(ring[i] + ring[j]);
}
}
let mut results = Vec::with_capacity(660);
for first in weapon {
for second in armor {
for &third in &combinations {
let Item { cost, damage, armor } = first + second + third;
let hero_turns = boss_health / (damage - boss_armor).max(1);
let boss_turns = 100 / (boss_damage - armor).max(1);
let win = hero_turns <= boss_turns;
results.push((win, cost));
}
}
}
results
}
pub fn part1(input: &[Result]) -> i32 {
*input.iter().filter_map(|(w, c)| w.then_some(c)).min().unwrap()
}
pub fn part2(input: &[Result]) -> i32 {
*input.iter().filter_map(|(w, c)| (!w).then_some(c)).max().unwrap()
}