day08 done.

This commit is contained in:
Gabe Venberg 2023-12-10 08:58:43 -06:00
parent c9e4dab862
commit 5b3a1c737f
5 changed files with 147 additions and 5 deletions

View file

@ -1,2 +1,3 @@
pub mod points; pub mod points;
pub mod range; pub mod range;
pub mod misc;

43
aoc_libs/src/misc.rs Normal file
View file

@ -0,0 +1,43 @@
pub fn arr_lcm(input: &[usize]) -> usize {
input.iter().copied().reduce(lcm).unwrap_or(0)
}
pub fn lcm(first: usize, second: usize) -> usize {
first * second / gcd(&first, &second)
}
pub fn gcd(a: &usize, b: &usize) -> usize {
let mut a = *a;
let mut b = *b;
while b != 0 {
let tmp = b;
b = a.rem_euclid(b);
a = tmp;
}
a
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_arr_lcm() {
assert_eq!(arr_lcm(&[4, 6]), 12);
assert_eq!(arr_lcm(&[5, 2]), 10);
assert_eq!(arr_lcm(&[5, 2, 6]), 30);
assert_eq!(arr_lcm(&[5, 2, 6, 3]), 30);
}
#[test]
fn test_lcm() {
assert_eq!(lcm(4, 6), 12);
assert_eq!(lcm(5, 2), 10);
}
#[test]
fn test_gcd() {
assert_eq!(gcd(&8, &12), 4);
assert_eq!(gcd(&54, &24), 6);
}
}

View file

@ -10,5 +10,5 @@ fn main() {
println!("Result: {}", part1::part1(&structured_input)); println!("Result: {}", part1::part1(&structured_input));
println!("Part Two"); println!("Part Two");
println!("Result: {}", part2::part2()); println!("Result: {}", part2::part2(&structured_input));
} }

View file

@ -16,7 +16,7 @@ pub struct Node {
} }
static NODE_REGEX: Lazy<Regex> = Lazy::new(|| { static NODE_REGEX: Lazy<Regex> = Lazy::new(|| {
Regex::new(r"^([[:alpha:]]{3}) = \(([[:alpha:]]{3}), ([[:alpha:]]{3})\)$").unwrap() Regex::new(r"^([[:alnum:]]{3}) = \(([[:alnum:]]{3}), ([[:alnum:]]{3})\)$").unwrap()
}); });
pub fn parse(input: &str) -> (Vec<Direction>, HashMap<String, Node>) { pub fn parse(input: &str) -> (Vec<Direction>, HashMap<String, Node>) {

View file

@ -1,15 +1,113 @@
use aoc_libs::misc::arr_lcm;
use std::collections::HashMap;
use crate::parse::*; use crate::parse::*;
pub fn part2() -> usize { // note about inputs: each "ends with A" node is the starting point,
unimplemented!() // and is not returned to part of the loop.
// eatch 'Z' node is at the 'end' of the loop,
// so the time when you first hit z is equal to your cycle time.
pub fn part2(input: &(Vec<Direction>, HashMap<String, Node>)) -> usize {
let (directions, graph) = input;
let starting_points = find_starting_points(graph);
println!("{:?}", starting_points);
let cycle_lengths: Vec<_> = starting_points
.iter()
.inspect(|p| print!("starting point {}: ", p))
.map(|p| cycle_len_and_offset(p, directions, graph))
.inspect(|c| println!("cycles: {}", c))
.collect();
arr_lcm(&cycle_lengths)
}
//returns the length of the loop
fn cycle_len_and_offset(
start: &str,
directions: &[Direction],
graph: &HashMap<String, Node>,
) -> usize {
let mut current_node: String = start.to_string();
let mut dir_index: usize = 0;
let mut cycles: usize = 0;
while !current_node.ends_with('Z') {
match directions[dir_index % directions.len()] {
Direction::Left => current_node = graph.get(&current_node).unwrap().left.clone(),
Direction::Right => current_node = graph.get(&current_node).unwrap().right.clone(),
};
cycles += 1;
dir_index += 1;
// println!("finding index: {}", current_node);
}
cycles
}
fn find_starting_points(input: &HashMap<String, Node>) -> Vec<String> {
let mut ret = Vec::new();
for point in input.keys() {
if point.ends_with('A') {
ret.push(point.to_string())
}
}
ret
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
#[test]
fn test_find_len_of_cycle() {
let input = parse(concat!(
"LR\n",
"\n",
"11A = (11B, XXX)\n",
"11B = (XXX, 11Z)\n",
"11Z = (11B, XXX)\n",
"22A = (22B, XXX)\n",
"22B = (22C, 22C)\n",
"22C = (22Z, 22Z)\n",
"22Z = (22B, 22B)\n",
"XXX = (XXX, XXX)\n",
));
assert_eq!(cycle_len_and_offset("11A", &input.0, &input.1), 2);
assert_eq!(cycle_len_and_offset("22A", &input.0, &input.1), 3);
}
#[test]
fn test_find_starting_points() {
let input = parse(concat!(
"LR\n",
"\n",
"11A = (11B, XXX)\n",
"11B = (XXX, 11Z)\n",
"11Z = (11B, XXX)\n",
"22A = (22B, XXX)\n",
"22B = (22C, 22C)\n",
"22C = (22Z, 22Z)\n",
"22Z = (22B, 22B)\n",
"XXX = (XXX, XXX)\n",
));
let starting_points = find_starting_points(&input.1);
assert_eq!(starting_points.len(), 2);
assert!(starting_points.contains(&"11A".to_string()));
assert!(starting_points.contains(&"22A".to_string()));
}
#[test] #[test]
fn test_part2() { fn test_part2() {
assert_eq!(0, 0); let input = parse(concat!(
"LR\n",
"\n",
"11A = (11B, XXX)\n",
"11B = (XXX, 11Z)\n",
"11Z = (11B, XXX)\n",
"22A = (22B, XXX)\n",
"22B = (22C, 22C)\n",
"22C = (22Z, 22Z)\n",
"22Z = (22B, 22B)\n",
"XXX = (XXX, XXX)\n",
));
assert_eq!(part2(&input), 6);
} }
} }