Optimize day 12 a little
Less clones and remove unnecessary one_small_twice check
This commit is contained in:
parent
830425c5fd
commit
e3352bb5ec
@ -1,37 +1,35 @@
|
|||||||
use anyhow::{anyhow, Error, Result};
|
use anyhow::{anyhow, Error, Result};
|
||||||
use common::instrument;
|
use common::instrument;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
const INPUT: &str = include_str!("input/input.txt");
|
const INPUT: &str = include_str!("input/input.txt");
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
enum Cave {
|
enum Cave<'a> {
|
||||||
Start,
|
Start,
|
||||||
End,
|
End,
|
||||||
Small(String),
|
Small(&'a str),
|
||||||
Big(String),
|
Big(&'a str),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Cave {
|
impl<'a> From<&'a str> for Cave<'a> {
|
||||||
type Err = Error;
|
fn from(s: &'a str) -> Self {
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self> {
|
|
||||||
if s == "start" {
|
if s == "start" {
|
||||||
Ok(Cave::Start)
|
Cave::Start
|
||||||
} else if s == "end" {
|
} else if s == "end" {
|
||||||
Ok(Cave::End)
|
Cave::End
|
||||||
} else {
|
} else {
|
||||||
match s.chars().all(|c| c.is_uppercase()) {
|
match s.chars().all(|c| c.is_uppercase()) {
|
||||||
true => Ok(Cave::Big(s.to_string())),
|
true => Cave::Big(s),
|
||||||
false => Ok(Cave::Small(s.to_string())),
|
false => Cave::Small(s),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Cave {
|
impl<'a> Display for Cave<'a> {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Cave::Start => write!(f, "start"),
|
Cave::Start => write!(f, "start"),
|
||||||
@ -43,24 +41,24 @@ impl Display for Cave {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
struct CaveSystem {
|
struct CaveSystem<'a> {
|
||||||
connections: HashMap<Cave, Vec<Cave>>,
|
connections: HashMap<Cave<'a>, Vec<Cave<'a>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for CaveSystem {
|
impl<'a> TryFrom<&'a str> for CaveSystem<'a> {
|
||||||
type Err = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self> {
|
fn try_from(s: &'a str) -> Result<Self> {
|
||||||
let mut connections = HashMap::new();
|
let mut connections = HashMap::new();
|
||||||
|
|
||||||
for line in s.trim().lines() {
|
for line in s.trim().lines() {
|
||||||
let mut parts = line.split('-');
|
let mut parts = line.split('-');
|
||||||
let origin = parts.next().ok_or(anyhow!("missing origin"))?;
|
let origin = parts.next().ok_or(anyhow!("missing origin"))?;
|
||||||
let origin = origin.parse::<Cave>()?;
|
let origin: Cave = origin.into();
|
||||||
let destination = parts.next().ok_or(anyhow!("missing destination"))?;
|
let destination = parts.next().ok_or(anyhow!("missing destination"))?;
|
||||||
let destination = destination.parse::<Cave>()?;
|
let destination: Cave = destination.into();
|
||||||
let entry = connections.entry(origin.clone()).or_insert_with(Vec::new);
|
let entry = connections.entry(origin).or_insert_with(Vec::new);
|
||||||
entry.push(destination.clone());
|
entry.push(destination);
|
||||||
let entry = connections.entry(destination).or_insert_with(Vec::new);
|
let entry = connections.entry(destination).or_insert_with(Vec::new);
|
||||||
entry.push(origin);
|
entry.push(origin);
|
||||||
}
|
}
|
||||||
@ -69,8 +67,8 @@ impl FromStr for CaveSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CaveSystem {
|
impl<'a> CaveSystem<'a> {
|
||||||
fn get_paths(&self, path: &Vec<Cave>, one_small_twice: bool) -> Result<Vec<Vec<Cave>>> {
|
fn get_paths(&self, path: &Vec<Cave<'a>>, one_small_twice: bool) -> Result<Vec<Vec<Cave>>> {
|
||||||
let mut paths = vec![];
|
let mut paths = vec![];
|
||||||
let origin = path.last().ok_or(anyhow!("empty path"))?;
|
let origin = path.last().ok_or(anyhow!("empty path"))?;
|
||||||
|
|
||||||
@ -80,38 +78,23 @@ impl CaveSystem {
|
|||||||
Cave::Start => continue,
|
Cave::Start => continue,
|
||||||
Cave::End => {
|
Cave::End => {
|
||||||
let mut path = path.clone();
|
let mut path = path.clone();
|
||||||
path.push(destination.clone());
|
path.push(*destination);
|
||||||
Ok(vec![path])
|
Ok(vec![path])
|
||||||
}
|
}
|
||||||
Cave::Big(_) => {
|
Cave::Big(_) => {
|
||||||
let mut path = path.clone();
|
let mut path = path.clone();
|
||||||
path.push(destination.clone());
|
path.push(*destination);
|
||||||
self.get_paths(&path, one_small_twice)
|
self.get_paths(&path, one_small_twice)
|
||||||
}
|
}
|
||||||
Cave::Small(_) => {
|
Cave::Small(_) => {
|
||||||
if !path.contains(destination) {
|
if !path.contains(destination) {
|
||||||
let mut path = path.clone();
|
let mut path = path.clone();
|
||||||
path.push(destination.clone());
|
path.push(*destination);
|
||||||
self.get_paths(&path, one_small_twice)
|
self.get_paths(&path, one_small_twice)
|
||||||
} else if one_small_twice {
|
} else if one_small_twice {
|
||||||
let mut small_counts = HashMap::new();
|
let mut path = path.clone();
|
||||||
for small in path.iter().filter(|c| {
|
path.push(*destination);
|
||||||
if let Cave::Small(_) = c {
|
self.get_paths(&path, false)
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
let entry = small_counts.entry(small.clone()).or_insert(0);
|
|
||||||
*entry += 1;
|
|
||||||
}
|
|
||||||
if small_counts.values().any(|&count| count > 1) {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
let mut path = path.clone();
|
|
||||||
path.push(destination.clone());
|
|
||||||
self.get_paths(&path, one_small_twice)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -124,7 +107,7 @@ impl CaveSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn solve_part1(input: &str) -> Result<usize> {
|
fn solve_part1(input: &str) -> Result<usize> {
|
||||||
let cave_system = input.parse::<CaveSystem>()?;
|
let cave_system: CaveSystem = input.try_into()?;
|
||||||
|
|
||||||
let paths = cave_system.get_paths(&vec![Cave::Start], false)?;
|
let paths = cave_system.get_paths(&vec![Cave::Start], false)?;
|
||||||
|
|
||||||
@ -132,7 +115,7 @@ fn solve_part1(input: &str) -> Result<usize> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn solve_part2(input: &str) -> Result<usize> {
|
fn solve_part2(input: &str) -> Result<usize> {
|
||||||
let cave_system = input.parse::<CaveSystem>()?;
|
let cave_system: CaveSystem = input.try_into()?;
|
||||||
|
|
||||||
let paths = cave_system.get_paths(&vec![Cave::Start], true)?;
|
let paths = cave_system.get_paths(&vec![Cave::Start], true)?;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user