Day 24 part 2.

This commit is contained in:
2023-11-14 19:35:00 +01:00
parent 3a9379f877
commit fc803d8a0f
2 changed files with 62 additions and 16 deletions

View File

@@ -1,3 +1,3 @@
fn main() { fn main() {
aoc_2018::tasks::day24::task1(); aoc_2018::tasks::day24::task2();
} }

View File

@@ -1,17 +1,32 @@
use std::cmp::Reverse; use std::cmp::Reverse;
use std::collections::HashMap; use std::collections::HashMap;
use itertools::Itertools;
use crate::utils; use crate::utils;
pub fn task1() { pub fn task1() {
let input = utils::read_file("input/day24.txt"); let input = utils::read_file("input/day24.txt");
let remaining_units = play(&input); let result = play(&input, 0);
println!("Standing units after the game: {}", remaining_units); println!("Standing units after the game: {}", result.unwrap().1);
} }
fn play(input: &str) -> i64 { pub fn task2() {
let mut game = Game::create(&input); let input = utils::read_file("input/day24.txt");
let immune_final_count = (0..)
.map(|boost| play(&input, boost))
.find(|result| result.map(|(team, _)| team) == Some(Team::ImmuneSystem))
.unwrap()
.unwrap()
.1;
println!("Immune systems final count: {immune_final_count}");
}
fn play(input: &str, boost: i64) -> Option<(Team, i64)> {
let mut game = Game::create(&input, boost);
println!( println!(
"Immune start units: {}", "Immune start units: {}",
@@ -30,18 +45,20 @@ fn play(input: &str) -> i64 {
.sum::<i64>() .sum::<i64>()
); );
let mut rounds_played = 0;
while !game.is_over() { while !game.is_over() {
game.round(); game.round();
rounds_played += 1; if game.draw {
return None;
}
} }
game.remaining_units() Some((game.winning_team(), game.remaining_units()))
} }
#[derive(Debug)] #[derive(Debug)]
struct Game { struct Game {
groups: HashMap<usize, Group>, groups: HashMap<usize, Group>,
draw: bool,
} }
impl Game { impl Game {
@@ -49,7 +66,20 @@ impl Game {
self.groups.values().map(|it| it.units).sum::<i64>() self.groups.values().map(|it| it.units).sum::<i64>()
} }
fn create(input: &str) -> Self { fn winning_team(&self) -> Team {
let teams: Vec<Team> = self
.groups
.values()
.map(|group| group.team)
.unique()
.collect();
if teams.len() != 1 {
panic!("No winning team. Remaining teams: {teams:?}");
}
teams[0]
}
fn create(input: &str, boost: i64) -> Self {
let mut groups = HashMap::new(); let mut groups = HashMap::new();
let mut team = Team::ImmuneSystem; let mut team = Team::ImmuneSystem;
for (id, line) in input.lines().enumerate() { for (id, line) in input.lines().enumerate() {
@@ -62,7 +92,10 @@ impl Game {
} }
"" => (), "" => (),
group => { group => {
if let Some(group) = Group::from_str(group, team, id) { if let Some(mut group) = Group::from_str(group, team, id) {
if group.team == Team::ImmuneSystem {
group.attack_damage += boost;
}
groups.insert(id, group); groups.insert(id, group);
} else { } else {
panic!("bad group: {group}"); panic!("bad group: {group}");
@@ -70,7 +103,10 @@ impl Game {
} }
} }
} }
Game { groups } Game {
groups,
draw: false,
}
} }
fn round(&mut self) { fn round(&mut self) {
@@ -125,6 +161,7 @@ impl Game {
let mut all_ids_by_initiative: Vec<usize> = self.groups.values().map(|it| it.id).collect(); let mut all_ids_by_initiative: Vec<usize> = self.groups.values().map(|it| it.id).collect();
all_ids_by_initiative.sort_unstable_by_key(|id| Reverse(self.groups[id].initiative)); all_ids_by_initiative.sort_unstable_by_key(|id| Reverse(self.groups[id].initiative));
self.draw = true;
for active_id in all_ids_by_initiative { for active_id in all_ids_by_initiative {
if !self.groups[&active_id].alive() { if !self.groups[&active_id].alive() {
// was killed in this round // was killed in this round
@@ -137,6 +174,9 @@ impl Game {
let dying_units = damage / enemy.hp_each; let dying_units = damage / enemy.hp_each;
self.groups.get_mut(enemy_id).unwrap().units -= dying_units; self.groups.get_mut(enemy_id).unwrap().units -= dying_units;
if dying_units > 0 {
self.draw = false;
}
// println!( // println!(
// "{} dealt {} ({} units) damage to {}", // "{} dealt {} ({} units) damage to {}",
// active_id, damage, dying_units, enemy_id // active_id, damage, dying_units, enemy_id
@@ -158,7 +198,7 @@ impl Game {
} }
} }
#[derive(Debug, Copy, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
enum Team { enum Team {
Infection, Infection,
ImmuneSystem, ImmuneSystem,
@@ -247,15 +287,21 @@ impl Group {
mod test { mod test {
use crate::tasks::day24::play; use crate::tasks::day24::play;
#[test] const INPUT: &str = "Immune System:
fn example1() {
let input = "Immune System:
17 units each with 5390 hit points (weak to radiation, bludgeoning) with an attack that does 4507 fire damage at initiative 2 17 units each with 5390 hit points (weak to radiation, bludgeoning) with an attack that does 4507 fire damage at initiative 2
989 units each with 1274 hit points (immune to fire; weak to bludgeoning, slashing) with an attack that does 25 slashing damage at initiative 3 989 units each with 1274 hit points (immune to fire; weak to bludgeoning, slashing) with an attack that does 25 slashing damage at initiative 3
Infection: Infection:
801 units each with 4706 hit points (weak to radiation) with an attack that does 116 bludgeoning damage at initiative 1 801 units each with 4706 hit points (weak to radiation) with an attack that does 116 bludgeoning damage at initiative 1
4485 units each with 2961 hit points (immune to radiation; weak to fire, cold) with an attack that does 12 slashing damage at initiative 4"; 4485 units each with 2961 hit points (immune to radiation; weak to fire, cold) with an attack that does 12 slashing damage at initiative 4";
assert_eq!(5216, play(input));
#[test]
fn example1() {
assert_eq!(5216, play(INPUT, 0).unwrap().1);
}
#[test]
fn example2() {
assert_eq!(51, play(INPUT, 1570).unwrap().1);
} }
} }