Day 8 2023 aoc part 1 solved, part 2 naive attempt that is very much too slow

This commit is contained in:
2024-02-13 09:44:52 +01:00
parent 1866aefc5b
commit a7d13bd73c
6 changed files with 1007 additions and 0 deletions

View File

@@ -0,0 +1,174 @@
use nom::{
bytes::complete::tag,
character::complete::{alpha1, alphanumeric1, multispace1},
multi::separated_list1,
sequence::{separated_pair, tuple},
IResult, Parser,
};
use std::collections::HashMap;
#[derive(Debug, Clone, Copy)]
enum Dir {
Right,
Left,
}
fn parse_input(input: &str) -> IResult<&str, (Vec<Dir>, Vec<(String, String, String)>)> {
use Dir::*;
let (input, result) = (separated_pair(
alpha1,
multispace1,
separated_list1(
multispace1,
tuple((
alphanumeric1::<&str, _>,
tag(" = ("),
alphanumeric1,
tag(", "),
alphanumeric1,
tag(")"),
))
.map(|(start, _, left, _, right, _)| {
(start.to_string(), left.to_string(), right.to_string())
}),
),
))(input)?;
let result = (
result
.0
.chars()
.map(|c| match c {
'R' => Right,
'L' => Left,
_ => unreachable!(),
})
.collect(),
result.1,
);
Ok((input, result))
}
fn create_network(network: &[(String, String, String)]) -> HashMap<String, (String, String)> {
let mut result = HashMap::new();
for (source, left, right) in network {
result.insert(source.to_owned(), (left.to_owned(), right.to_owned()));
}
result
}
fn solve_1(route: &[Dir], network: &Vec<(String, String, String)>) -> u32 {
use Dir::*;
let network = create_network(&network[..]);
let mut current_node = "AAA".to_string();
let mut steps = 0;
let mut route_iter = route.iter();
loop {
if current_node == "ZZZ".to_string() {
return steps;
}
steps += 1;
let direction = match route_iter.next() {
None => {
route_iter = route.iter();
route_iter.next().unwrap()
}
Some(dir) => dir,
};
current_node = match direction {
Right => network.get(&current_node).unwrap().1.to_owned(),
Left => network.get(&current_node).unwrap().0.to_owned(),
}
}
}
fn solve_2(route: &[Dir], network: &Vec<(String, String, String)>) -> u32 {
use Dir::*;
let mut current_nodes = network
.iter()
.filter(|(start, _left, _right)| start.ends_with('A'))
.map(|(start, _left, _right)| start.to_owned())
.collect::<Vec<String>>();
let network = create_network(&network[..]);
let mut steps = 0;
let mut route_iter = route.iter();
loop {
if current_nodes.iter().all(|node| node.ends_with('Z')) {
return steps;
}
steps += 1;
let direction = match route_iter.next() {
None => {
route_iter = route.iter();
route_iter.next().unwrap()
}
Some(dir) => dir,
};
for node in current_nodes.iter_mut() {
let target_node = match direction {
Right => network.get(node).unwrap().1.to_owned(),
Left => network.get(node).unwrap().0.to_owned(),
};
*node = target_node.to_owned();
}
}
}
fn main() {
println!("Hello, this is Patrick!");
let input_text = include_str!("../input.txt");
let (_, (route, network)) = parse_input(input_text).unwrap();
println!(
"There are {} steps required to reach ZZZ",
solve_1(&route[..], &network)
);
println!(
"There are {} steps required to reach only nodes ending on Z, when starting from nodes ending only on A",
solve_2(&route[..], &network)
);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test1_part1() {
let input_text = include_str!("../test_input1.txt");
let (_, (route, network)) = parse_input(input_text).unwrap();
assert_eq!(solve_1(&route[..], &network), 2);
}
#[test]
fn test2_part1() {
let input_text = include_str!("../test_input2.txt");
let (_, (route, network)) = parse_input(input_text).unwrap();
assert_eq!(solve_1(&route[..], &network), 6);
}
#[test]
fn test_part2() {
let input_text = include_str!("../test_input3.txt");
let (_, (route, network)) = parse_input(input_text).unwrap();
assert_eq!(solve_2(&route[..], &network), 6);
}
}