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 day19;
|
||||
mod day20;
|
||||
mod day21;
|
||||
|
||||
aoc_lib! { year = 2015 }
|
||||
|
||||
Reference in New Issue
Block a user