diff --git a/.vscode/launch.json b/.vscode/launch.json index d1f66fe..f6b3fe2 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -7,15 +7,15 @@ { "type": "lldb", "request": "launch", - "name": "Debug executable 'advent2019'", + "name": "Debug executable 'advent2022'", "cargo": { "args": [ "build", - "--bin=advent2019", - "--package=advent2019" + "--bin=advent2022", + "--package=advent2022" ], "filter": { - "name": "advent2019", + "name": "advent2022", "kind": "bin" } }, @@ -30,16 +30,16 @@ { "type": "lldb", "request": "launch", - "name": "Debug unit tests in executable 'advent2019'", + "name": "Debug unit tests in executable 'advent2022'", "cargo": { "args": [ "test", "--no-run", - "--bin=advent2019", - "--package=advent2019" + "--bin=advent2022", + "--package=advent2022" ], "filter": { - "name": "advent2019", + "name": "advent2022", "kind": "bin" } }, diff --git a/.vscode/settings.json b/.vscode/settings.json index 23fd35f..5f484b7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "editor.formatOnSave": true + "editor.formatOnSave": true, + "debug.allowBreakpointsEverywhere": true } \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index d4af544..cbeeee5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,6 @@ edition = "2021" anyhow = "1.0" const_format = "0.2.31" itertools = "0.11" -lazy_static = "1.4" num-traits = "0.2" once_cell = "1.18.0" regex = "1.7" diff --git a/src/days/day11/mod.rs b/src/days/day11/mod.rs index 0f2cd1e..2e8b3c7 100644 --- a/src/days/day11/mod.rs +++ b/src/days/day11/mod.rs @@ -1,5 +1,5 @@ use super::template::{DayTrait, ResultType}; -use lazy_static::lazy_static; +use once_cell::sync::Lazy; use regex::Regex; use std::{iter::zip, num::ParseIntError}; use thiserror::Error; @@ -72,13 +72,14 @@ struct Monkey { bad_monkey: usize, } -lazy_static! { - static ref MONKEY: Regex = Regex::new(r"Monkey (\d+)").unwrap(); - static ref STARTING: Regex = Regex::new(r"Starting items: (\d+(?:, \d+)*)").unwrap(); - static ref OP: Regex = Regex::new(r"Operation: new = old ([+*] \d+|\* old)").unwrap(); - static ref TEST: Regex = Regex::new(r"Test: divisible by (\d+)").unwrap(); - static ref NEXT: Regex = Regex::new(r"If (?:true|false): throw to monkey (\d+)").unwrap(); -} +static MONKEY: Lazy = Lazy::new(|| Regex::new(r"Monkey (\d+)").unwrap()); +static STARTING: Lazy = + Lazy::new(|| Regex::new(r"Starting items: (\d+(?:, \d+)*)").unwrap()); +static OP: Lazy = + Lazy::new(|| Regex::new(r"Operation: new = old ([+*] \d+|\* old)").unwrap()); +static TEST: Lazy = Lazy::new(|| Regex::new(r"Test: divisible by (\d+)").unwrap()); +static NEXT: Lazy = + Lazy::new(|| Regex::new(r"If (?:true|false): throw to monkey (\d+)").unwrap()); impl Monkey { fn parse_line<'a>(re: &Regex, line: &'a str) -> Result<&'a str, MonkeyError> { diff --git a/src/days/day15/mod.rs b/src/days/day15/mod.rs index 0614b9e..28e4ee4 100644 --- a/src/days/day15/mod.rs +++ b/src/days/day15/mod.rs @@ -1,7 +1,7 @@ use super::template::{DayTrait, ResultType}; use crate::common::pos::Pos; use itertools::Itertools; -use lazy_static::lazy_static; +use once_cell::sync::Lazy; use regex::Regex; use std::{collections::HashSet, num::ParseIntError}; use thiserror::Error; @@ -209,9 +209,8 @@ struct Sensor { radius: i64, } -lazy_static! { - static ref SENSOR: Regex = Regex::new(r"x=(-?\d+), y=(-?\d+).*x=(-?\d+), y=(-?\d+)").unwrap(); -} +static SENSOR: Lazy = + Lazy::new(|| Regex::new(r"x=(-?\d+), y=(-?\d+).*x=(-?\d+), y=(-?\d+)").unwrap()); impl Sensor { pub fn parse(line: &str) -> Result<(Sensor, Pos), SensorError> { diff --git a/src/days/day16/mod.rs b/src/days/day16/mod.rs index 1f5e13b..1e7cfb1 100644 --- a/src/days/day16/mod.rs +++ b/src/days/day16/mod.rs @@ -1,7 +1,13 @@ -use std::num::ParseIntError; +use std::collections::HashMap; +use std::fmt::{Debug, Display}; +use std::hash::Hash; +use std::iter::Sum; +use std::ops::{Add, Deref, Mul, Sub}; +use std::{collections::BinaryHeap, num::ParseIntError}; use super::template::{DayTrait, ResultType}; use const_format::concatcp; +use itertools::Itertools; use once_cell::sync::Lazy; use regex::Regex; use thiserror::Error; @@ -16,11 +22,106 @@ impl DayTrait for Day { } fn part1(&self, lines: &[String]) -> anyhow::Result { - Ok(ResultType::Nothing) + let system = ValveSystem::build(lines, "AA")?; + let result = system.maximum_flow(system.single_actor(Time(30)))?; + Ok(ResultType::Integer(*result)) } fn part2(&self, lines: &[String]) -> anyhow::Result { - Ok(ResultType::Nothing) + let system = ValveSystem::build(lines, "AA")?; + let result = system.maximum_flow(system.double_actor(Time(26)))?; + Ok(ResultType::Integer(*result)) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +struct Time(usize); + +impl Time { + #[inline] + fn sub_to_zero(&self, other: Time) -> Time { + if self.0 > other.0 { + Time(self.0 - other.0) + } else { + Time(0) + } + } + + #[inline] + fn inc(&self) -> Self { + Self(self.0 + 1) + } +} + +impl Deref for Time { + type Target = usize; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Add for Time { + type Output = Self; + + #[inline] + fn add(self, rhs: Self) -> Self::Output { + Self(self.0 + rhs.0) + } +} + +impl Sub for Time { + type Output = Self; + + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + Self(self.0 - rhs.0) + } +} + +impl Mul for Time { + type Output = Flow; + + fn mul(self, rhs: Flow) -> Self::Output { + Flow(self.0 as i64 * *rhs) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +struct Flow(i64); +impl Deref for Flow { + type Target = i64; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Add for Flow { + type Output = Self; + + #[inline] + fn add(self, rhs: Self) -> Self::Output { + Self(self.0 + rhs.0) + } +} + +impl Sum for Flow { + fn sum>(iter: I) -> Self { + iter.fold(Self(0), |a, b| a + b) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +struct Index(usize); + +impl Deref for Index { + type Target = usize; + + fn deref(&self) -> &Self::Target { + &self.0 } } @@ -29,8 +130,14 @@ enum ValveError { #[error("Not an Integer")] NotAnInt(#[from] ParseIntError), + #[error("Not a valid description: {0}")] + CouldNotParse(String), + #[error("Not a valid valve: {0}")] - NotAValidValve(String), + ValveNotFound(String), + + #[error("Did nt find optimum flow")] + NoOptimumFound, } const ID: &str = "[[:alpha:]]+"; @@ -46,80 +153,759 @@ const PLURAL_STR: &str = concatcp!( const SINGULAR_STR: &str = concatcp!(COMMON, "tunnel leads to valve (?", ID, ")$"); #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] -struct Valve { - id: String, - rate: i64, - distances: Vec<(String, i64)>, +struct RawValve<'a> { + id: &'a str, + flow: Flow, + neighbors: Vec<&'a str>, } -impl Valve { - fn from_regex(regex: &Regex, line: &str) -> Option> { +impl<'a> RawValve<'a> { + fn create(id: &'a str, flow: Flow, neighbors: Vec<&'a str>) -> Self { + RawValve { + id, + flow, + neighbors, + } + } + + fn from_regex(regex: &Regex, line: &'a str) -> Option, ValveError>> { regex.captures(line).map(|caps| { match (caps.name("id"), caps.name("rate"), caps.name("exits")) { (Some(id), Some(rate), Some(exits)) => { let rate = rate.as_str().parse()?; - let distances = exits - .as_str() - .split(",") - .map(|s| (s.trim_start().to_string(), 1)) - .collect(); - Ok(Valve { - id: id.as_str().to_string(), - rate, - distances, - }) + let neighbors = exits.as_str().split(",").map(|s| s.trim_start()).collect(); + Ok(RawValve::create(id.as_str(), Flow(rate), neighbors)) } - _ => Err(ValveError::NotAValidValve(line.to_string())), + _ => Err(ValveError::CouldNotParse(line.to_string())), } }) } - - pub fn known_distances(&self) -> usize { - self.distances.len() + 1 - } - - pub fn steps_to(&self, to: &str) -> Option { - self.distances - .iter() - .find_map(|(other, distance)| if other == to { Some(*distance) } else { None }) - .or_else(|| (to == self.id).then_some(0)) - } } -impl TryFrom<&str> for Valve { +impl<'a> TryFrom<&'a str> for RawValve<'a> { type Error = ValveError; - fn try_from(value: &str) -> Result { + fn try_from(value: &'a str) -> Result, Self::Error> { static PLURAL: Lazy = Lazy::new(|| Regex::new(PLURAL_STR).unwrap()); static SINGULAR: Lazy = Lazy::new(|| Regex::new(SINGULAR_STR).unwrap()); - Valve::from_regex(&PLURAL, value) - .or_else(|| Valve::from_regex(&SINGULAR, value)) - .unwrap_or_else(|| Err(ValveError::NotAValidValve(value.to_string()))) + RawValve::from_regex(&PLURAL, value) + .or_else(|| RawValve::from_regex(&SINGULAR, value)) + .unwrap_or_else(|| Err(ValveError::CouldNotParse(value.to_string()))) } } -struct System { +#[derive(Debug)] +struct Valve { + id: String, + idx: Index, + flow: Flow, + distances: Vec