Day 8 2023 aoc part 1 solved, part 2 naive attempt that is very much too slow
This commit is contained in:
174
advent_of_code/2023/8/src/main.rs
Normal file
174
advent_of_code/2023/8/src/main.rs
Normal 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(¤t_node).unwrap().1.to_owned(),
|
||||
Left => network.get(¤t_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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user