day11, part2; pretty much just stolen from chris biscardi

This commit is contained in:
Joe Ardent 2025-01-12 11:07:16 -08:00
parent 9fe31c237a
commit 6d09e0a718

View file

@ -1,4 +1,4 @@
use std::collections::VecDeque; use std::collections::HashMap;
fn main() { fn main() {
let input = std::fs::read_to_string("input").unwrap(); let input = std::fs::read_to_string("input").unwrap();
@ -7,142 +7,65 @@ fn main() {
println!("{}", pt2(&stones)); println!("{}", pt2(&stones));
} }
fn pt1(stones: &[u128]) -> usize { fn pt1(stones: &[u64]) -> usize {
blink2(stones, 25) b4(stones, 25)
} }
fn pt2(stones: &[u128]) -> usize { fn pt2(stones: &[u64]) -> usize {
let mut total = 0; b4(stones, 75)
for stone in stones { }
total += b4(vec![*stone], 75);
fn b4(stones: &[u64], blinks: usize) -> usize {
let mut cache = HashMap::new();
for &stone in stones {
cache.entry(stone).and_modify(|n| *n += 1).or_insert(1usize);
} }
total
}
fn blink2(stones: &[u128], blinks: usize) -> usize {
let mut stones = VecDeque::from_iter(stones.iter().copied());
for _blink in 0..blinks { for _blink in 0..blinks {
let mut rots = 0; let mut new_cache = HashMap::new();
while rots < stones.len() { for (stone, count) in cache.into_iter() {
let stone = stones[0];
let digits = stone.to_string();
match stone { match stone {
0 => { 0 => {
stones[0] = 1; new_cache
stones.rotate_left(1); .entry(1)
rots += 1; .and_modify(|n| *n += count)
.or_insert(count);
} }
_ if digits.len() % 2 == 0 => { _ if (stone.checked_ilog10().unwrap_or(0) + 1) % 2 == 0 => {
let mid = digits.len() / 2; let (left, right) = split(stone);
let left = digits[0..mid].parse().unwrap(); new_cache
let right = digits[mid..].parse().unwrap(); .entry(left)
stones[0] = left; .and_modify(|n| *n += count)
stones.rotate_left(1); .or_insert(count);
stones.push_front(right); new_cache
stones.rotate_left(1); .entry(right)
rots += 2; .and_modify(|n| *n += count)
.or_insert(count);
} }
_ => { _ => {
stones[0] = stone * 2024; let new = stone * 2024;
stones.rotate_left(1); new_cache
rots += 1; .entry(new)
.and_modify(|n| *n += count)
.or_insert(count);
} }
} }
} }
stones.rotate_right(rots); cache = new_cache;
}
stones.len()
}
fn b4(stones: Vec<u128>, blinks: usize) -> usize {
let mut total = stones.len();
let mut stones = VecDeque::from_iter(stones);
for blink in 0..blinks {
let len = stones.len();
if len > 10_000_000 {
println!("splitting; started with {blinks} blinks to go, blinked {blink} times");
let mid = len / 2;
let stones = stones.make_contiguous().to_vec();
let iter = &mut stones.into_iter();
let left: Vec<_> = iter.take(mid).collect();
let right: Vec<_> = iter.collect();
// otherwise it gets double-counted at the start of the function in the
// recursive call
total -= left.len();
total -= right.len();
let blinks = blinks - blink;
total += b4(left, blinks);
total += b4(right, blinks);
break;
} else {
let mut rots = 0;
while rots < stones.len() {
let stone = stones[0];
let digits = stone.to_string();
match stone {
0 => {
stones[0] = 1;
stones.rotate_left(1);
rots += 1;
}
_ if digits.len() % 2 == 0 => {
let mid = digits.len() / 2;
let left = digits[0..mid].parse().unwrap();
let right = digits[mid..].parse().unwrap();
stones[0] = left;
stones.rotate_left(1);
stones.push_front(right);
stones.rotate_left(1);
rots += 2;
total += 1;
}
_ => {
stones[0] = stone * 2024;
stones.rotate_left(1);
rots += 1;
}
}
}
stones.rotate_right(rots);
}
}
total
}
fn blink3(mut stones: Vec<u128>, blinks: usize) -> usize {
let mut total = stones.len();
for blink in 0..blinks {
let mut rights = Vec::new();
for stone in stones.iter_mut() {
let digits = stone.to_string();
match stone {
0 => {
*stone = 1;
}
_ if digits.len() % 2 == 0 => {
let mid = digits.len() / 2;
let left = digits[0..mid].parse().unwrap();
let right = digits[mid..].parse().unwrap();
*stone = left;
rights.push(right);
total += 1;
}
_ => {
*stone *= 2024;
}
}
}
total += blink3(rights, blinks - blink);
} }
total cache.values().sum()
} }
fn parse(input: &str) -> Vec<u128> { fn split(num: u64) -> (u64, u64) {
let num_digits = num.ilog10() + 1;
let div = num_digits / 2;
let left = num.div_euclid(10u64.pow(div));
let right = num.rem_euclid(10u64.pow(div));
(left, right)
}
fn parse(input: &str) -> Vec<u64> {
input input
.trim() .trim()
.split(' ') .split(' ')
@ -159,10 +82,4 @@ mod test {
let stones = parse("125 17"); let stones = parse("125 17");
assert_eq!(55312, pt1(&stones)); assert_eq!(55312, pt1(&stones));
} }
#[test]
fn p2() {
let stones = parse("125 17");
assert_eq!(55312, b4(stones, 25));
}
} }