Day 8 part 2, easy peasy Least Common Multiple
This commit is contained in:
parent
cab03a2ed5
commit
82fc810e11
4 changed files with 138 additions and 75 deletions
|
@ -2,11 +2,7 @@ use aoc23::prelude::*;
|
|||
use derive_builder::Builder;
|
||||
use itertools::Itertools;
|
||||
use rayon::prelude::*;
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
str::FromStr,
|
||||
time::Instant,
|
||||
};
|
||||
use std::{cmp::Ordering, str::FromStr, time::Instant};
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
|
||||
enum Strength {
|
||||
|
@ -38,7 +34,9 @@ impl Strength {
|
|||
// for possible real hands like full house etc, need to branch off and try all
|
||||
// combinations...
|
||||
counts.iter().fold(Strength::HighCard, |strength, &count| {
|
||||
std::cmp::max(strength.clone(), match count {
|
||||
std::cmp::max(
|
||||
strength.clone(),
|
||||
match count {
|
||||
5 => Strength::FiveOfAKind,
|
||||
4 => Strength::FourOfAKind,
|
||||
3 => match strength {
|
||||
|
@ -52,7 +50,8 @@ impl Strength {
|
|||
_ => Strength::OnePair,
|
||||
},
|
||||
_ => strength,
|
||||
})
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -62,7 +61,9 @@ impl Strength {
|
|||
for card in hand.cards.iter() {
|
||||
counts[*card as usize - 2] += 1;
|
||||
}
|
||||
counts.iter().fold(Strength::HighCard, |strength, &count| match count {
|
||||
counts
|
||||
.iter()
|
||||
.fold(Strength::HighCard, |strength, &count| match count {
|
||||
5 => Strength::FiveOfAKind,
|
||||
4 => Strength::FourOfAKind,
|
||||
3 => match strength {
|
||||
|
@ -116,7 +117,13 @@ impl FromStr for Hand {
|
|||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
let mut splits = s.trim().split_whitespace();
|
||||
Ok(HandBuilder::default().cards(splits.next().unwrap().chars().map(|c| {
|
||||
Ok(HandBuilder::default()
|
||||
.cards(
|
||||
splits
|
||||
.next()
|
||||
.unwrap()
|
||||
.chars()
|
||||
.map(|c| {
|
||||
if let Some(digit) = c.to_digit(10) {
|
||||
digit
|
||||
} else {
|
||||
|
@ -141,14 +148,17 @@ impl FromStr for Hand {
|
|||
_ => panic!("invalid card: {}", c),
|
||||
}
|
||||
}
|
||||
}).collect()).bid(splits.next().unwrap().parse()?).build()?)
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
.bid(splits.next().unwrap().parse()?)
|
||||
.build()?)
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate(input: String) -> Result<usize> {
|
||||
let start = Instant::now();
|
||||
let answer =
|
||||
input
|
||||
let answer = input
|
||||
.lines()
|
||||
.map(|line| line.parse::<Hand>().unwrap())
|
||||
.sorted()
|
||||
|
|
|
@ -2,13 +2,19 @@ use aoc23::prelude::*;
|
|||
use derive_builder::Builder;
|
||||
use itertools::Itertools;
|
||||
use rayon::prelude::*;
|
||||
use std::{collections::HashMap, time::Instant};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
io::{self, Write},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
extern crate regex;
|
||||
|
||||
use regex::Regex;
|
||||
use static_init::dynamic;
|
||||
|
||||
// Regex is slow to compile, don't do it in the parse loop, pull it out here and
|
||||
// compile it once and reuse below.
|
||||
#[dynamic]
|
||||
static RE_PARSE_NODE: Regex =
|
||||
Regex::new(r"(?<id>\w{3}).*?(?<left>\w{3}).*?(?<right>\w{3})").expect("re_parse_node invalid");
|
||||
|
@ -22,8 +28,6 @@ struct Node<'a> {
|
|||
|
||||
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}))")?
|
||||
// let re = Regex::new(r"(?`<id>`\w{3})._?(?`<left>`\w{3})._?(?`<right>`\w{3})")?
|
||||
let re = RE_PARSE_NODE.captures(s).expect("No match for regex");
|
||||
Ok(NodeBuilder::default()
|
||||
.id(re.name("id").expect("no id").as_str())
|
||||
|
@ -108,7 +112,7 @@ fn part1(input: String) -> Result<usize> {
|
|||
Ok(answer)
|
||||
}
|
||||
|
||||
fn part2(input: String) -> Result<usize> {
|
||||
fn part2(input: String) -> Result<u64> {
|
||||
// parse
|
||||
let start = Instant::now();
|
||||
let map: Map = Map::new(&input)?;
|
||||
|
@ -116,7 +120,25 @@ fn part2(input: String) -> Result<usize> {
|
|||
|
||||
// algo
|
||||
let start = Instant::now();
|
||||
let answer = 0;
|
||||
let currents: Vec<&Node> = map.nodes.values().filter(|n| n.id.ends_with("A")).collect();
|
||||
let steps: Vec<u64> = currents
|
||||
.par_iter()
|
||||
.map(|node| {
|
||||
let mut dir = map.dirs.iter().cycle();
|
||||
let mut steps = 0;
|
||||
let mut current = *node;
|
||||
while !current.id.ends_with("Z") {
|
||||
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"),
|
||||
}
|
||||
steps += 1;
|
||||
// println!("Step: {answer}"); let _ = std::io::stdout().flush();
|
||||
}
|
||||
steps
|
||||
})
|
||||
.collect();
|
||||
let answer = utils::math::find_lcm(&steps[..]);
|
||||
let algo_time = start.elapsed();
|
||||
|
||||
// output
|
||||
|
@ -133,8 +155,7 @@ async fn main() -> Result<()> {
|
|||
println!("=====");
|
||||
let input = utils::aoc::get_puzzle_input(DAY).await?;
|
||||
part1(input.clone())?;
|
||||
|
||||
// part2(input.clone())?;
|
||||
part2(input.clone())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -145,7 +166,7 @@ mod tests {
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_part_1_b() -> Result<()> {
|
||||
fn test_part_1() -> Result<()> {
|
||||
assert_eq!(
|
||||
part1(
|
||||
"RL
|
||||
|
@ -174,6 +195,22 @@ ZZZ = (ZZZ, ZZZ)"
|
|||
);
|
||||
Ok(())
|
||||
}
|
||||
// #[test] fn test_part_2() -> Result<()> {
|
||||
// assert_eq!(part2("REPLACE".to_owned())?, 0); Ok(()) }
|
||||
|
||||
#[test]
|
||||
fn test_part_2() -> Result<()> {
|
||||
part2(
|
||||
"LR
|
||||
|
||||
11A = (11B, XXX)
|
||||
11B = (XXX, 11Z)
|
||||
11Z = (11B, XXX)
|
||||
22A = (22B, XXX)
|
||||
22B = (22C, 22C)
|
||||
22C = (22Z, 22Z)
|
||||
22Z = (22B, 22B)
|
||||
XXX = (XXX, XXX)"
|
||||
.to_owned(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
15
src/utils/math.rs
Normal file
15
src/utils/math.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
fn gcd(a: u64, b: u64) -> u64 {
|
||||
if b == 0 {
|
||||
a
|
||||
} else {
|
||||
gcd(b, a % b)
|
||||
}
|
||||
}
|
||||
|
||||
fn lcm(a: u64, b: u64) -> u64 {
|
||||
a / gcd(a, b) * b
|
||||
}
|
||||
|
||||
pub fn find_lcm(numbers: &[u64]) -> u64 {
|
||||
numbers.iter().cloned().fold(1, |acc, num| lcm(acc, num))
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
pub mod aoc;
|
||||
pub mod common;
|
||||
pub mod config;
|
||||
pub mod math;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue