Day 24 part 1.

This commit is contained in:
2023-11-14 18:48:31 +01:00
parent 241c417a77
commit 3a9379f877

View File

@@ -8,8 +8,6 @@ pub fn task1() {
let remaining_units = play(&input); let remaining_units = play(&input);
println!("Standing units after the game: {}", remaining_units); println!("Standing units after the game: {}", remaining_units);
// 21107 too high
// 21004 too high
} }
fn play(input: &str) -> i64 { fn play(input: &str) -> i64 {
@@ -38,10 +36,7 @@ fn play(input: &str) -> i64 {
rounds_played += 1; rounds_played += 1;
} }
println!("{:#?}", game); game.remaining_units()
println!("Played {} rounds", rounds_played);
game.groups.values().map(|it| it.units).sum::<i64>()
} }
#[derive(Debug)] #[derive(Debug)]
@@ -50,6 +45,10 @@ struct Game {
} }
impl Game { impl Game {
fn remaining_units(&self) -> i64 {
self.groups.values().map(|it| it.units).sum::<i64>()
}
fn create(input: &str) -> Self { fn create(input: &str) -> Self {
let mut groups = HashMap::new(); let mut groups = HashMap::new();
let mut team = Team::ImmuneSystem; let mut team = Team::ImmuneSystem;
@@ -65,6 +64,8 @@ impl Game {
group => { group => {
if let Some(group) = Group::from_str(group, team, id) { if let Some(group) = Group::from_str(group, team, id) {
groups.insert(id, group); groups.insert(id, group);
} else {
panic!("bad group: {group}");
} }
} }
} }
@@ -77,22 +78,21 @@ impl Game {
// lock targets ordered by effective power // lock targets ordered by effective power
let mut all_by_power: Vec<&Group> = self.groups.values().collect(); let mut all_by_power: Vec<&Group> = self.groups.values().collect();
all_by_power.sort_unstable_by_key(|a| Reverse((a.effective_power(), a.initiative))); all_by_power.sort_unstable_by_key(|a| Reverse((a.effective_power(), a.initiative)));
for group in all_by_power.iter() { // for group in all_by_power.iter() {
println!( // println!(
"{}: {} ({})", // "{}: {} ({})",
group.id, // group.id,
group.effective_power(), // group.effective_power(),
group.initiative // group.initiative
); // );
} // }
println!("{:?}", all_by_power); // println!("{:?}", all_by_power);
for group in all_by_power.iter() { for group in all_by_power.iter() {
if let Some(t) = self if let Some(t) = self
.groups .groups
.values() .values()
.filter(|it| it.team != group.team) .filter(|it| it.team != group.team)
.filter(|it| !target.values().any(|t| *t == it.id)) .filter(|it| !target.values().any(|t| *t == it.id))
// .filter(|it| group.compute_attack_damage_to(&it) >= it.hp_each)
// .inspect(|it| { // .inspect(|it| {
// println!( // println!(
// "{} would deal {} damage to {}", // "{} would deal {} damage to {}",
@@ -110,10 +110,10 @@ impl Game {
}) })
{ {
if group.compute_attack_damage_to(t) <= 0 { if group.compute_attack_damage_to(t) <= 0 {
println!( // println!(
"Didn't find a target where {:?} can deal positive damage.", // "Didn't find a target where {:?} can deal positive damage.",
group // group
); // );
continue; continue;
} else { } else {
target.insert(group.id, t.id); target.insert(group.id, t.id);
@@ -128,20 +128,19 @@ impl Game {
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
println!("Group {} already dead", active_id); // println!("Group {} already dead", active_id);
continue; continue;
} }
if let Some(enemy_id) = target.get(&active_id) { if let Some(enemy_id) = target.get(&active_id) {
let enemy = &self.groups[enemy_id]; let enemy = &self.groups[enemy_id];
let damage: i64 = self.groups[&active_id].compute_attack_damage_to(enemy); let damage: i64 = self.groups[&active_id].compute_attack_damage_to(enemy);
let dying_units = damage / enemy.hp_each; let dying_units = damage / enemy.hp_each;
if let Some(enemy) = self.groups.get_mut(enemy_id) { self.groups.get_mut(enemy_id).unwrap().units -= dying_units;
enemy.units -= dying_units;
} // println!(
println!( // "{} dealt {} ({} units) damage to {}",
"{} dealt {} ({} units) damage to {}", // active_id, damage, dying_units, enemy_id
active_id, damage, dying_units, enemy_id // );
);
} }
} }
@@ -151,8 +150,7 @@ impl Game {
} }
fn is_over(&self) -> bool { fn is_over(&self) -> bool {
self.groups.is_empty() self.groups.iter().all(|(_, it)| it.team == Team::Infection)
|| self.groups.iter().all(|(_, it)| it.team == Team::Infection)
|| self || self
.groups .groups
.iter() .iter()
@@ -182,8 +180,9 @@ struct Group {
impl Group { impl Group {
fn from_str(input: &str, team: Team, id: usize) -> Option<Self> { fn from_str(input: &str, team: Team, id: usize) -> Option<Self> {
// 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
// 2347 units each with 3322 hit points with an attack that does 12 cold damage at initiative 2
use regex::Regex; use regex::Regex;
let regex = Regex::new(r"(\d+) units each with (\d+) hit points \((.+)\) with an attack that does (\d+) (\w+) damage at initiative (\d+)").unwrap(); let regex = Regex::new(r"(\d+) units each with (\d+) hit points(.*)with an attack that does (\d+) (\w+) damage at initiative (\d+)").unwrap();
if let Some(m) = regex.captures(input) { if let Some(m) = regex.captures(input) {
let units: i64 = m[1].parse().unwrap(); let units: i64 = m[1].parse().unwrap();
let hp_each: i64 = m[2].parse().unwrap(); let hp_each: i64 = m[2].parse().unwrap();
@@ -192,7 +191,8 @@ impl Group {
let initiative: u64 = m[6].parse().unwrap(); let initiative: u64 = m[6].parse().unwrap();
let mut weaknesses: Vec<String> = Vec::new(); let mut weaknesses: Vec<String> = Vec::new();
let mut immunities: Vec<String> = Vec::new(); let mut immunities: Vec<String> = Vec::new();
for part in m[3].split("; ") { let attributes = m[3].trim().trim_start_matches("(").trim_end_matches(")");
for part in attributes.split("; ") {
if let Some(stripped) = part.strip_prefix("weak to ") { if let Some(stripped) = part.strip_prefix("weak to ") {
weaknesses = stripped.split(", ").map(|it| it.to_string()).collect(); weaknesses = stripped.split(", ").map(|it| it.to_string()).collect();
} else if let Some(stripped) = part.strip_prefix("immune to ") { } else if let Some(stripped) = part.strip_prefix("immune to ") {