day 21
This commit is contained in:
161
src/day21.rs
Normal file
161
src/day21.rs
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
use std::cmp::max;
|
||||||
|
|
||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
|
||||||
|
#[aoc_generator(day21)]
|
||||||
|
fn parse(input: &str) -> Fighter {
|
||||||
|
let ints: Vec<i32> = input
|
||||||
|
.lines()
|
||||||
|
.map(|line| line.split_once(": ").unwrap().1)
|
||||||
|
.map(|it| it.parse().unwrap())
|
||||||
|
.collect();
|
||||||
|
Fighter {
|
||||||
|
health: ints[0],
|
||||||
|
damage: ints[1],
|
||||||
|
armor: ints[2],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
struct Fighter {
|
||||||
|
health: i32,
|
||||||
|
damage: i32,
|
||||||
|
armor: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct Item {
|
||||||
|
cost: i32,
|
||||||
|
damage: i32,
|
||||||
|
armor: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Item {
|
||||||
|
fn new(cost: i32, damage: i32, armor: i32) -> Self {
|
||||||
|
Self {
|
||||||
|
cost,
|
||||||
|
damage,
|
||||||
|
armor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[aoc(day21, part1)]
|
||||||
|
fn part1(boss: &Fighter) -> usize {
|
||||||
|
combinations()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|(fighter, _)| fight(*fighter, *boss))
|
||||||
|
.map(|(_, cost)| cost)
|
||||||
|
// .count()
|
||||||
|
.min()
|
||||||
|
.unwrap() as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns `true` if `fighter` wins the fight
|
||||||
|
fn fight(mut fighter: Fighter, mut boss: Fighter) -> bool {
|
||||||
|
loop {
|
||||||
|
boss.health -= max(1, fighter.damage - boss.armor);
|
||||||
|
if boss.health < 1 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
fighter.health -= max(1, boss.damage - fighter.armor);
|
||||||
|
if fighter.health < 1 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn combinations() -> Vec<(Fighter, i32)> {
|
||||||
|
let (weapons, armors, rings) = items();
|
||||||
|
let mut all_rings = vec![Item::new(0, 0, 0)];
|
||||||
|
for r1 in 0..rings.len() {
|
||||||
|
let ring1 = rings[r1];
|
||||||
|
all_rings.push(ring1);
|
||||||
|
for ring2 in rings.iter().skip(r1 + 1) {
|
||||||
|
all_rings.push(Item::new(
|
||||||
|
ring1.cost + ring2.cost,
|
||||||
|
ring1.damage + ring2.damage,
|
||||||
|
ring1.armor + ring2.armor,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut result = vec![];
|
||||||
|
|
||||||
|
for weapon in weapons {
|
||||||
|
for &armor in &armors {
|
||||||
|
for &ring in &all_rings {
|
||||||
|
let cost = weapon.cost + armor.cost + ring.cost;
|
||||||
|
let health = 100;
|
||||||
|
let damage = weapon.damage + ring.damage;
|
||||||
|
let armor = armor.armor + ring.armor;
|
||||||
|
result.push((
|
||||||
|
Fighter {
|
||||||
|
health,
|
||||||
|
damage,
|
||||||
|
armor,
|
||||||
|
},
|
||||||
|
cost,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day21, part2)]
|
||||||
|
fn part2(boss: &Fighter) -> usize {
|
||||||
|
combinations()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|(fighter, _)| !fight(*fighter, *boss))
|
||||||
|
.map(|(_, cost)| cost)
|
||||||
|
.max()
|
||||||
|
.unwrap() as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn items() -> (Vec<Item>, Vec<Item>, Vec<Item>) {
|
||||||
|
let weapons = vec![
|
||||||
|
Item::new(8, 4, 0),
|
||||||
|
Item::new(10, 5, 0),
|
||||||
|
Item::new(25, 6, 0),
|
||||||
|
Item::new(40, 7, 0),
|
||||||
|
Item::new(74, 8, 0),
|
||||||
|
];
|
||||||
|
let armors = vec![
|
||||||
|
Item::new(0, 0, 0), // because we need the option to have no armor
|
||||||
|
Item::new(13, 0, 1),
|
||||||
|
Item::new(31, 0, 2),
|
||||||
|
Item::new(53, 0, 3),
|
||||||
|
Item::new(75, 0, 4),
|
||||||
|
Item::new(102, 0, 5),
|
||||||
|
];
|
||||||
|
let rings = vec![
|
||||||
|
Item::new(25, 1, 0),
|
||||||
|
Item::new(50, 2, 0),
|
||||||
|
Item::new(100, 3, 0),
|
||||||
|
Item::new(20, 0, 1),
|
||||||
|
Item::new(40, 0, 2),
|
||||||
|
Item::new(80, 0, 3),
|
||||||
|
];
|
||||||
|
(weapons, armors, rings)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::day21::{fight, Fighter};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_case() {
|
||||||
|
assert!(fight(
|
||||||
|
Fighter {
|
||||||
|
health: 8,
|
||||||
|
damage: 5,
|
||||||
|
armor: 5,
|
||||||
|
},
|
||||||
|
Fighter {
|
||||||
|
health: 12,
|
||||||
|
damage: 7,
|
||||||
|
armor: 2,
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,5 +13,6 @@ mod day17;
|
|||||||
mod day18;
|
mod day18;
|
||||||
mod day19;
|
mod day19;
|
||||||
mod day20;
|
mod day20;
|
||||||
|
mod day21;
|
||||||
|
|
||||||
aoc_lib! { year = 2015 }
|
aoc_lib! { year = 2015 }
|
||||||
|
|||||||
Reference in New Issue
Block a user