This commit is contained in:
2024-10-30 23:29:32 +01:00
parent ef83390c02
commit eba60c4c97
2 changed files with 162 additions and 0 deletions

161
src/day21.rs Normal file
View 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,
}
))
}
}

View File

@@ -13,5 +13,6 @@ mod day17;
mod day18;
mod day19;
mod day20;
mod day21;
aoc_lib! { year = 2015 }