Compare commits
3 Commits
a4c33ae3d2
...
3a9379f877
| Author | SHA1 | Date | |
|---|---|---|---|
| 3a9379f877 | |||
| 241c417a77 | |||
| 4cbe831115 |
@@ -1,3 +1,3 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
aoc_2018::tasks::day21::task1();
|
aoc_2018::tasks::day24::task1();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -277,6 +277,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_AddR() {
|
fn test_AddR() {
|
||||||
let op = Op::AddR;
|
let op = Op::AddR;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -292,6 +293,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_AddI() {
|
fn test_AddI() {
|
||||||
let op = Op::AddI;
|
let op = Op::AddI;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -307,6 +309,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_MulR() {
|
fn test_MulR() {
|
||||||
let op = Op::MulR;
|
let op = Op::MulR;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -322,6 +325,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_MulI() {
|
fn test_MulI() {
|
||||||
let op = Op::MulI;
|
let op = Op::MulI;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -337,6 +341,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_BanR() {
|
fn test_BanR() {
|
||||||
let op = Op::BanR;
|
let op = Op::BanR;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -352,6 +357,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_BanI() {
|
fn test_BanI() {
|
||||||
let op = Op::BanI;
|
let op = Op::BanI;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -367,6 +373,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_BorR() {
|
fn test_BorR() {
|
||||||
let op = Op::BorR;
|
let op = Op::BorR;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -382,6 +389,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_BorI() {
|
fn test_BorI() {
|
||||||
let op = Op::BorI;
|
let op = Op::BorI;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -397,6 +405,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_SetR() {
|
fn test_SetR() {
|
||||||
let op = Op::SetR;
|
let op = Op::SetR;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -412,6 +421,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_SetI() {
|
fn test_SetI() {
|
||||||
let op = Op::SetI;
|
let op = Op::SetI;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -427,6 +437,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_GtIR_true() {
|
fn test_GtIR_true() {
|
||||||
let op = Op::GtIR;
|
let op = Op::GtIR;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -442,6 +453,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_GtIR_false() {
|
fn test_GtIR_false() {
|
||||||
let op = Op::GtIR;
|
let op = Op::GtIR;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -457,6 +469,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_GtRI_true() {
|
fn test_GtRI_true() {
|
||||||
let op = Op::GtRI;
|
let op = Op::GtRI;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -472,6 +485,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_GtRI_false() {
|
fn test_GtRI_false() {
|
||||||
let op = Op::GtRI;
|
let op = Op::GtRI;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -487,6 +501,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_GtRR_true() {
|
fn test_GtRR_true() {
|
||||||
let op = Op::GtRR;
|
let op = Op::GtRR;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -502,6 +517,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_GtRR() {
|
fn test_GtRR() {
|
||||||
let op = Op::GtRR;
|
let op = Op::GtRR;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -517,6 +533,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_EqIR_true() {
|
fn test_EqIR_true() {
|
||||||
let op = Op::EqIR;
|
let op = Op::EqIR;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -532,6 +549,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_EqIR_false() {
|
fn test_EqIR_false() {
|
||||||
let op = Op::EqIR;
|
let op = Op::EqIR;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -547,6 +565,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_EqRI_true() {
|
fn test_EqRI_true() {
|
||||||
let op = Op::EqRI;
|
let op = Op::EqRI;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -562,6 +581,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_EqRI_false() {
|
fn test_EqRI_false() {
|
||||||
let op = Op::EqRI;
|
let op = Op::EqRI;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -577,6 +597,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_EqRR_true() {
|
fn test_EqRR_true() {
|
||||||
let op = Op::EqRR;
|
let op = Op::EqRR;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
@@ -592,6 +613,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn test_EqRR_false() {
|
fn test_EqRR_false() {
|
||||||
let op = Op::EqRR;
|
let op = Op::EqRR;
|
||||||
let result = op.process(
|
let result = op.process(
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
use crate::utils;
|
|
||||||
use std::cmp::Reverse;
|
use std::cmp::Reverse;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub fn task1() {
|
use crate::utils;
|
||||||
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
|
|
||||||
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:
|
pub fn task1() {
|
||||||
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";
|
|
||||||
let input = utils::read_file("input/day24.txt");
|
let input = utils::read_file("input/day24.txt");
|
||||||
|
|
||||||
|
let remaining_units = play(&input);
|
||||||
|
println!("Standing units after the game: {}", remaining_units);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn play(input: &str) -> i64 {
|
||||||
let mut game = Game::create(&input);
|
let mut game = Game::create(&input);
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
@@ -36,16 +36,7 @@ Infection:
|
|||||||
rounds_played += 1;
|
rounds_played += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{:#?}", game);
|
game.remaining_units()
|
||||||
println!("Played {} rounds", rounds_played);
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"Standing units after the game: {}",
|
|
||||||
game.groups.values().map(|it| it.units).sum::<i64>()
|
|
||||||
);
|
|
||||||
|
|
||||||
// 21107 too high
|
|
||||||
// 21004 too high
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -54,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;
|
||||||
@@ -69,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}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,7 +93,6 @@ impl Game {
|
|||||||
.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 {}",
|
||||||
@@ -114,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);
|
||||||
@@ -132,16 +128,15 @@ 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
|
||||||
@@ -155,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()
|
||||||
@@ -186,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();
|
||||||
@@ -196,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 ") {
|
||||||
@@ -246,3 +242,20 @@ impl Group {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::tasks::day24::play;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
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
|
||||||
|
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:
|
||||||
|
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";
|
||||||
|
assert_eq!(5216, play(input));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user