advent_of_code/src/bin/day8.rs
RingOfStorms (Joshua Bell) e4ab3fb81e day 8 part 1, but its slow
2023-12-08 00:52:17 -06:00

175 lines
4 KiB
Rust

use aoc23::prelude::*;
use derive_builder::Builder;
use itertools::Itertools;
use rayon::prelude::*;
use std::{collections::HashMap, str::FromStr, time::Instant};
extern crate regex;
use regex::Regex;
use std::error::Error;
#[derive(Debug, Builder, Clone)]
struct Node<'a> {
id: &'a str,
left: &'a str,
right: &'a str,
}
impl<'a> Node<'a> {
fn new(s: &'a str) -> Result<Self> {
let re = Regex::new(r"(?<id>\w{3}).*?(?<left>\w{3}).*?(?<right>\w{3})")?
.captures(s)
.expect("No match for regex");
Ok(NodeBuilder::default()
.id(re.name("id").expect("no id").as_str())
.left(re.name("left").expect("no left").as_str())
.right(re.name("right").expect("no right").as_str())
.build()?)
}
}
#[derive(Debug, Clone)]
enum Dir {
Left,
Right,
}
impl Dir {
fn from_char(c: &char) -> Self {
match c {
'L' => Self::Left,
'R' => Self::Right,
_ => panic!("Not valid dir"),
}
}
}
#[derive(Debug, Builder, Clone)]
struct Map<'a> {
dirs: Vec<Dir>,
nodes: HashMap<&'a str, Node<'a>>,
}
impl<'a> Map<'a> {
fn new(s: &'a str) -> Result<Self> {
let mut splits = s.trim().split("\n\n");
Ok(MapBuilder::default()
.dirs(
splits
.next()
.unwrap()
.trim()
.chars()
.map(|c| Dir::from_char(&c))
.collect(),
)
.nodes(
splits
.next()
.unwrap()
.trim()
.lines()
.map(|a| Node::new(a.trim()).map(|n| (n.id, n)))
.try_collect()?,
)
.build()?)
}
}
fn part1(input: String) -> Result<usize> {
// parse
let start = Instant::now();
let map: Map = Map::new(&input)?;
let parsed_time = start.elapsed();
// algo
let start = Instant::now();
let mut answer = 0;
let mut current = map.nodes.get("AAA").expect("no start node");
let mut dir = map.dirs.iter().cycle();
while !current.id.eq("ZZZ") {
match dir.next().unwrap() {
Dir::Left => current = map.nodes.get(current.left).expect("no left node"),
Dir::Right => current = map.nodes.get(current.right).expect("no right node"),
}
answer += 1;
}
let algo_time = start.elapsed();
// output
println!("Day 5, part 1: {answer}");
println!("\tparse: {parsed_time:?}");
println!("\talgo: {algo_time:?}");
Ok(answer)
}
fn part2(input: String) -> Result<usize> {
// parse
let start = Instant::now();
let map: Map = Map::new(&input)?;
let parsed_time = start.elapsed();
// algo
let start = Instant::now();
let answer = 0;
let algo_time = start.elapsed();
// output
println!("Day 5, part 2: {answer}");
println!("\tparse: {parsed_time:?}");
println!("\talgo: {algo_time:?}");
Ok(answer)
}
// TODO come back and revise for a faster solution
#[tokio::main]
async fn main() -> Result<()> {
println!("Day {DAY}");
println!("=====");
let input = utils::aoc::get_puzzle_input(DAY).await?;
part1(input.clone())?;
// part2(input.clone())?;
Ok(())
}
static DAY: u8 = 8;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_part_1_b() -> Result<()> {
assert_eq!(
part1(
"RL
AAA = (BBB, CCC)
BBB = (DDD, EEE)
CCC = (ZZZ, GGG)
DDD = (DDD, DDD)
EEE = (EEE, EEE)
GGG = (GGG, GGG)
ZZZ = (ZZZ, ZZZ)"
.to_owned(),
)?,
2
);
assert_eq!(
part1(
"LLR
AAA = (BBB, BBB)
BBB = (AAA, ZZZ)
ZZZ = (ZZZ, ZZZ)"
.to_owned()
)?,
6
);
Ok(())
}
// #[test] fn test_part_2() -> Result<()> {
// assert_eq!(part2("REPLACE".to_owned())?, 0); Ok(()) }
}