From 00000380c3be4b81839b641fb253a472ecf0a4fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Jane=C5=BEi=C4=8D?= Date: Tue, 13 Dec 2022 22:19:24 +0100 Subject: [PATCH] solution: day22 --- src/bin/22.rs | 211 +++++++++++++++++++++++++++++++++++++++++ src/test_inputs/22.txt | 2 + 2 files changed, 213 insertions(+) create mode 100644 src/bin/22.rs create mode 100644 src/test_inputs/22.txt diff --git a/src/bin/22.rs b/src/bin/22.rs new file mode 100644 index 000000000..2b04482 --- /dev/null +++ b/src/bin/22.rs @@ -0,0 +1,211 @@ +use std::cmp::max; + +use itertools::Itertools; +use lazy_static::lazy_static; + +#[derive(Clone, Copy)] +struct Player { + hp: i32, + damage: i32, + mana: i32, +} + +#[derive(Debug, Clone)] +struct Spell { + name: String, + timer: i32, + damage: i32, + armor: i32, + heal: i32, + mana: i32, + cost: i32, +} + +lazy_static! { + static ref SPELLS: [Spell; 5] = [ + Spell { + name: "Magic Missile".to_string(), + timer: 1, + damage: 4, + armor: 0, + heal: 0, + mana: 0, + cost: 53, + }, + Spell { + name: "Drain".to_string(), + timer: 1, + damage: 2, + armor: 0, + heal: 2, + mana: 0, + cost: 73, + }, + Spell { + name: "Shield".to_string(), + timer: 6, + damage: 0, + armor: 7, + heal: 0, + mana: 0, + cost: 113, + }, + Spell { + name: "Poison".to_string(), + timer: 6, + damage: 3, + armor: 0, + heal: 0, + mana: 0, + cost: 173, + }, + Spell { + name: "Recharge".to_string(), + timer: 5, + damage: 0, + armor: 0, + heal: 0, + mana: 101, + cost: 229, + }, + ]; +} + +fn optimize_fight( + mut boss: Player, + mut player: Player, + players_turn: bool, + mut active_spells: Vec, + best_cost: &mut i32, + cost: i32, + hardmode: bool, +) { + if cost > *best_cost { + return; + } + let mut remaining = active_spells + .drain(..) + .filter(|x| x.timer > 0) + .collect_vec(); + let mut armor = 0; + for spell in remaining.iter_mut() { + spell.timer -= 1; + boss.hp -= spell.damage; + armor += spell.armor; + player.hp += spell.heal; + player.mana += spell.mana; + } + + if hardmode && players_turn { + player.hp -= 1; + } + if player.hp <= 0 { + return; + } + if boss.hp <= 0 { + if cost < *best_cost { + *best_cost = cost; + } + return; + } + + if players_turn { + let current = remaining + .iter() + .filter(|x| x.timer > 0) + .map(|x| x.name.to_string()) + .collect_vec(); + for spell in SPELLS + .iter() + .filter(|x| !current.contains(&x.name) && x.cost < player.mana) + .collect_vec() + { + let mut new_spells = remaining.to_vec(); + new_spells.push(spell.clone()); + let mut c = player; + c.mana -= spell.cost; + optimize_fight( + boss, + c, + !players_turn, + new_spells, + best_cost, + cost + spell.cost, + hardmode, + ); + } + } else { + let damage = max(boss.damage - armor, 1); + player.hp -= damage; + optimize_fight( + boss, + player, + !players_turn, + remaining, + best_cost, + cost, + hardmode, + ); + } +} + +pub fn part_one(input: &str) -> Option { + let (hp, damage) = input + .split('\n') + .map(|x| x.split(": ").last().unwrap().parse::().unwrap()) + .next_tuple() + .unwrap(); + let boss = Player { + hp, + damage, + mana: 0, + }; + let me = Player { + hp: 50, + damage: 0, + mana: 500, + }; + // this takes 7minutes but iiwii + let mut best_score = i32::max_value(); + optimize_fight(boss, me, true, vec![], &mut best_score, 0, false); + Some(best_score) +} +pub fn part_two(input: &str) -> Option { + let (hp, damage) = input + .split('\n') + .map(|x| x.split(": ").last().unwrap().parse::().unwrap()) + .next_tuple() + .unwrap(); + let boss = Player { + hp, + damage, + mana: 0, + }; + let me = Player { + hp: 50, + damage: 0, + mana: 500, + }; + let mut best_score = i32::max_value(); + optimize_fight(boss, me, true, vec![], &mut best_score, 0, true); + Some(best_score) +} +fn main() { + let input = &aoc::read_file("inputs", 22); + aoc::solve!(1, part_one, input); + aoc::solve!(2, part_two, input); +} +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_part_one() { + let input = aoc::read_file("test_inputs", 22); + assert_eq!(part_one(input.trim()), Some(212)); + } + #[test] + fn test_part_two() { + let input = aoc::read_file("test_inputs", 22); + assert_eq!(part_two(input.trim()), Some(212)); + } +} diff --git a/src/test_inputs/22.txt b/src/test_inputs/22.txt new file mode 100644 index 000000000..8b0b636 --- /dev/null +++ b/src/test_inputs/22.txt @@ -0,0 +1,2 @@ +Hit Points: 14 +Damage: 8