day16 started

This commit is contained in:
Rüdiger Ludwig 2023-07-16 18:54:54 +02:00
parent 96fca503ab
commit daa8b6b1d0
3 changed files with 140 additions and 5 deletions

View file

@ -1,4 +1,10 @@
use std::num::ParseIntError;
use super::template::{DayTrait, ResultType};
use const_format::concatcp;
use once_cell::sync::Lazy;
use regex::Regex;
use thiserror::Error;
const DAY_NUMBER: usize = 16;
@ -9,15 +15,114 @@ impl DayTrait for Day {
DAY_NUMBER
}
fn part1(&self, _lines: &[String]) -> anyhow::Result<ResultType> {
fn part1(&self, lines: &[String]) -> anyhow::Result<ResultType> {
Ok(ResultType::Nothing)
}
fn part2(&self, _lines: &[String]) -> anyhow::Result<ResultType> {
fn part2(&self, lines: &[String]) -> anyhow::Result<ResultType> {
Ok(ResultType::Nothing)
}
}
#[derive(Debug, Error)]
enum ValveError {
#[error("Not an Integer")]
NotAnInt(#[from] ParseIntError),
#[error("Not a valid valve: {0}")]
NotAValidValve(String),
}
const ID: &str = "[[:alpha:]]+";
const COMMON: &str = concatcp!("^Valve (?<id>", ID, r") has flow rate=(?<rate>\d+); ");
const PLURAL_STR: &str = concatcp!(
COMMON,
"tunnels lead to valves (?<exits>",
ID,
"(?:, ",
ID,
")+)$"
);
const SINGULAR_STR: &str = concatcp!(COMMON, "tunnel leads to valve (?<exits>", ID, ")$");
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct Valve {
id: String,
rate: i64,
distances: Vec<(String, i64)>,
}
impl Valve {
fn from_regex(regex: &Regex, line: &str) -> Option<Result<Valve, 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,
})
}
_ => Err(ValveError::NotAValidValve(line.to_string())),
}
})
}
pub fn known_distances(&self) -> usize {
self.distances.len() + 1
}
pub fn steps_to(&self, to: &str) -> Option<i64> {
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 {
type Error = ValveError;
fn try_from(value: &str) -> Result<Valve, Self::Error> {
static PLURAL: Lazy<Regex> = Lazy::new(|| Regex::new(PLURAL_STR).unwrap());
static SINGULAR: Lazy<Regex> = 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())))
}
}
struct System {
valves: Vec<Valve>,
}
impl System {
pub fn get_valve(&self, id: &str) -> Option<&Valve> {
self.valves.iter().find(|valve| valve.id == id)
}
pub fn len(&self) -> usize {
self.valves.len()
}
}
impl System {
fn build(lines: &[String]) -> Result<System, ValveError> {
Ok(System {
valves: lines
.iter()
.map(|line| Valve::try_from(line.as_str()))
.collect::<Result<Vec<_>, _>>()?,
})
}
}
#[cfg(test)]
mod test {
use super::*;
@ -45,4 +150,32 @@ mod test {
Ok(())
}
#[test]
fn parse_plural() -> Result<()> {
let line = "Valve BB has flow rate=13; tunnels lead to valves CC, AA";
let expected = Valve {
id: "BB".to_string(),
rate: 13,
distances: vec![("CC".to_string(), 1), ("AA".to_string(), 1)],
};
let result = Valve::try_from(line)?;
assert_eq!(expected, result);
Ok(())
}
#[test]
fn parse_singular() -> Result<()> {
let line = "Valve HH has flow rate=22; tunnel leads to valve GG";
let expected = Valve {
id: "HH".to_string(),
rate: 22,
distances: vec![("GG".to_string(), 1)],
};
let result = Valve::try_from(line)?;
assert_eq!(expected, result);
Ok(())
}
}