day24 p1 wrong (example ok)
This commit is contained in:
@@ -0,0 +1,23 @@
|
|||||||
|
Immune System:
|
||||||
|
3400 units each with 1430 hit points (immune to fire, radiation, slashing) with an attack that does 4 radiation damage at initiative 4
|
||||||
|
138 units each with 8650 hit points (weak to bludgeoning; immune to slashing, cold, radiation) with an attack that does 576 slashing damage at initiative 16
|
||||||
|
255 units each with 9469 hit points (weak to radiation, fire) with an attack that does 351 bludgeoning damage at initiative 8
|
||||||
|
4145 units each with 2591 hit points (immune to cold; weak to slashing) with an attack that does 6 fire damage at initiative 12
|
||||||
|
3605 units each with 10989 hit points with an attack that does 26 fire damage at initiative 19
|
||||||
|
865 units each with 11201 hit points with an attack that does 102 slashing damage at initiative 10
|
||||||
|
633 units each with 10092 hit points (weak to slashing, radiation) with an attack that does 150 slashing damage at initiative 11
|
||||||
|
2347 units each with 3322 hit points with an attack that does 12 cold damage at initiative 2
|
||||||
|
7045 units each with 3877 hit points (weak to radiation) with an attack that does 5 bludgeoning damage at initiative 5
|
||||||
|
1086 units each with 8626 hit points (weak to radiation) with an attack that does 69 slashing damage at initiative 13
|
||||||
|
|
||||||
|
Infection:
|
||||||
|
2152 units each with 12657 hit points (weak to fire, cold) with an attack that does 11 fire damage at initiative 18
|
||||||
|
40 units each with 39458 hit points (immune to radiation, fire, slashing; weak to bludgeoning) with an attack that does 1519 slashing damage at initiative 7
|
||||||
|
59 units each with 35138 hit points (immune to radiation; weak to fire) with an attack that does 1105 fire damage at initiative 15
|
||||||
|
1569 units each with 51364 hit points (weak to radiation) with an attack that does 55 radiation damage at initiative 17
|
||||||
|
929 units each with 23887 hit points (weak to bludgeoning) with an attack that does 48 cold damage at initiative 14
|
||||||
|
5264 units each with 14842 hit points (immune to cold, fire; weak to slashing, bludgeoning) with an attack that does 4 bludgeoning damage at initiative 9
|
||||||
|
1570 units each with 30419 hit points (weak to radiation, cold; immune to fire) with an attack that does 35 slashing damage at initiative 1
|
||||||
|
1428 units each with 21393 hit points (weak to radiation) with an attack that does 29 cold damage at initiative 6
|
||||||
|
1014 units each with 25717 hit points (weak to fire) with an attack that does 47 fire damage at initiative 3
|
||||||
|
7933 units each with 29900 hit points (immune to bludgeoning, radiation, slashing) with an attack that does 5 slashing damage at initiative 20
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
use crate::utils;
|
||||||
|
use std::cmp::Reverse;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub fn task1() {
|
pub fn task1() {
|
||||||
let input = "Immune System:
|
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
|
||||||
@@ -6,37 +10,172 @@ pub fn task1() {
|
|||||||
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";
|
||||||
let mut groups_immune: Vec<Group> = Vec::new();
|
let input = utils::read_file("input/day24.txt");
|
||||||
let mut groups_infection: Vec<Group> = Vec::new();
|
let mut game = Game::create(&input);
|
||||||
|
|
||||||
let mut to_immune = false;
|
println!(
|
||||||
for line in input.lines() {
|
"Immune start units: {}",
|
||||||
match line {
|
game.groups
|
||||||
"Immune System:" => {
|
.iter()
|
||||||
to_immune = true;
|
.filter(|(_, it)| it.team == Team::ImmuneSystem)
|
||||||
}
|
.map(|(_, it)| it.units)
|
||||||
"Infection:" => {
|
.sum::<i64>()
|
||||||
to_immune = false;
|
);
|
||||||
}
|
println!(
|
||||||
"" => (),
|
"Infection start units: {}",
|
||||||
group => {
|
game.groups
|
||||||
if let Some(group) = Group::from_str(group) {
|
.iter()
|
||||||
if to_immune {
|
.filter(|(_, it)| it.team == Team::Infection)
|
||||||
groups_immune.push(group);
|
.map(|(_, it)| it.units)
|
||||||
} else {
|
.sum::<i64>()
|
||||||
groups_infection.push(group);
|
);
|
||||||
}
|
|
||||||
}
|
let mut rounds_played = 0;
|
||||||
}
|
while !game.is_over() {
|
||||||
}
|
game.round();
|
||||||
|
rounds_played += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("Immune System:\n{:?}", groups_immune);
|
println!("{:#?}", game);
|
||||||
println!("Infection:\n{:?}", groups_infection);
|
println!("Played {} rounds", rounds_played);
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Standing units after the game: {}",
|
||||||
|
game.groups.iter().map(|(_, it)| it.units).sum::<i64>()
|
||||||
|
);
|
||||||
|
|
||||||
|
// 21107 too high
|
||||||
|
// 21004 too high
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
struct Game {
|
||||||
|
groups: HashMap<usize, Group>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Game {
|
||||||
|
fn create(input: &str) -> Self {
|
||||||
|
let mut groups = HashMap::new();
|
||||||
|
let mut team = Team::ImmuneSystem;
|
||||||
|
for (id, line) in input.lines().enumerate() {
|
||||||
|
match line {
|
||||||
|
"Immune System:" => {
|
||||||
|
team = Team::ImmuneSystem;
|
||||||
|
}
|
||||||
|
"Infection:" => {
|
||||||
|
team = Team::Infection;
|
||||||
|
}
|
||||||
|
"" => (),
|
||||||
|
group => {
|
||||||
|
if let Some(group) = Group::from_str(group, team, id) {
|
||||||
|
groups.insert(id, group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Game { groups }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn round(&mut self) {
|
||||||
|
let mut target: HashMap<usize, usize> = HashMap::new();
|
||||||
|
// lock targets ordered by effective power
|
||||||
|
let mut all_by_power: Vec<&Group> = self.groups.iter().map(|(_, it)| it).collect();
|
||||||
|
all_by_power.sort_unstable_by_key(|a| Reverse((a.effective_power(), a.initiative)));
|
||||||
|
// for group in all_by_power.iter() {
|
||||||
|
// println!(
|
||||||
|
// "{}: {} ({})",
|
||||||
|
// group.id,
|
||||||
|
// group.effective_power(),
|
||||||
|
// group.initiative
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// println!("{:?}", all_by_power);
|
||||||
|
for group in all_by_power.iter() {
|
||||||
|
if let Some(t) = self
|
||||||
|
.groups
|
||||||
|
.iter()
|
||||||
|
.map(|(_, it)| it)
|
||||||
|
.filter(|it| it.team != group.team)
|
||||||
|
.filter(|it| !target.values().any(|t| *t == it.id))
|
||||||
|
// .filter(|it| group.compute_attack_damage_to(&it) >= it.hp_each)
|
||||||
|
// .inspect(|it| {
|
||||||
|
// println!(
|
||||||
|
// "{} would deal {} damage to {}",
|
||||||
|
// group.id,
|
||||||
|
// group.compute_attack_damage_to(it),
|
||||||
|
// it.id
|
||||||
|
// )
|
||||||
|
// })
|
||||||
|
.max_by_key(|it| {
|
||||||
|
(
|
||||||
|
group.compute_attack_damage_to(&it),
|
||||||
|
it.effective_power(),
|
||||||
|
it.initiative,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
{
|
||||||
|
if group.compute_attack_damage_to(&t) <= 0 {
|
||||||
|
println!(
|
||||||
|
"Didn't find a target where {:?} can deal positive damage.",
|
||||||
|
group
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
target.insert(group.id, t.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// attack ordered by initiative
|
||||||
|
let mut all_ids_by_initiative: Vec<usize> =
|
||||||
|
self.groups.iter().map(|(_, it)| it.id).collect();
|
||||||
|
all_ids_by_initiative.sort_unstable_by_key(|id| Reverse(self.groups[id].initiative));
|
||||||
|
|
||||||
|
for active_id in all_ids_by_initiative {
|
||||||
|
if !self.groups[&active_id].alive() {
|
||||||
|
// was killed in this round
|
||||||
|
println!("Group {} already dead", active_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Some(enemy_id) = target.get(&active_id) {
|
||||||
|
let enemy = &self.groups[enemy_id];
|
||||||
|
let damage: i64 = self.groups[&active_id].compute_attack_damage_to(&enemy);
|
||||||
|
let dying_units = damage / enemy.hp_each;
|
||||||
|
if let Some(enemy) = self.groups.get_mut(enemy_id) {
|
||||||
|
enemy.units -= dying_units;
|
||||||
|
}
|
||||||
|
// println!(
|
||||||
|
// "{} dealt {} ({} units) damage to {}",
|
||||||
|
// active_id, damage, dying_units, enemy_id
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean up dead groups
|
||||||
|
self.groups.retain(|_, it| it.alive());
|
||||||
|
// println!("{:?}", self.groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_over(&self) -> bool {
|
||||||
|
self.groups.len() == 0
|
||||||
|
|| self.groups.iter().all(|(_, it)| it.team == Team::Infection)
|
||||||
|
|| self
|
||||||
|
.groups
|
||||||
|
.iter()
|
||||||
|
.all(|(_, it)| it.team == Team::ImmuneSystem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
enum Team {
|
||||||
|
Infection,
|
||||||
|
ImmuneSystem,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
struct Group {
|
struct Group {
|
||||||
|
id: usize,
|
||||||
|
team: Team,
|
||||||
units: i64,
|
units: i64,
|
||||||
hp_each: i64,
|
hp_each: i64,
|
||||||
weaknesses: Vec<String>,
|
weaknesses: Vec<String>,
|
||||||
@@ -47,7 +186,7 @@ struct Group {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Group {
|
impl Group {
|
||||||
fn from_str(input: &str) -> 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
|
||||||
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();
|
||||||
@@ -68,6 +207,8 @@ impl Group {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let group = Group {
|
let group = Group {
|
||||||
|
id,
|
||||||
|
team,
|
||||||
units,
|
units,
|
||||||
hp_each,
|
hp_each,
|
||||||
weaknesses,
|
weaknesses,
|
||||||
@@ -81,4 +222,29 @@ impl Group {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn alive(&self) -> bool {
|
||||||
|
self.units > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn effective_power(&self) -> i64 {
|
||||||
|
if !self.alive() {
|
||||||
|
panic!("I have no power, im dead!")
|
||||||
|
}
|
||||||
|
self.units * self.attack_damage
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_attack_damage_to(&self, other: &Self) -> i64 {
|
||||||
|
if self.alive() {
|
||||||
|
if other.weaknesses.contains(&self.attack_type) {
|
||||||
|
self.effective_power() * 2
|
||||||
|
} else if other.immunities.contains(&self.attack_type) {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
self.effective_power()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("I'm not alive, I cannot attack anyone")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user