Skip to content

Instantly share code, notes, and snippets.

@jmikkola
Created December 11, 2024 16:14
Show Gist options
  • Save jmikkola/23cb0097465603d3abd0dd7e2ba66236 to your computer and use it in GitHub Desktop.
Save jmikkola/23cb0097465603d3abd0dd7e2ba66236 to your computer and use it in GitHub Desktop.
use std::env;
use std::fs;
use std::collections::HashMap;
fn get_arg() -> String {
match env::args().nth(1) {
Some(f) => f,
None => "example".into(),
}
}
fn get_content(filename: String) -> String {
fs::read_to_string(filename).unwrap().trim().to_string()
}
fn parse_line(line: String) -> Vec<i64> {
line.split_whitespace().map(|part| {part.parse().unwrap()}).collect()
}
fn main() {
let stones = parse_line(get_content(get_arg()));
println!("Part 1: {}", part1(&stones));
println!("Part 2: {}", part2(&stones));
}
fn part2(stones: &[i64]) -> i64 {
let mut cache = HashMap::new();
let mut total = 0;
for stone in stones.iter() {
total += blink_cached(&mut cache, *stone, 75);
}
total
}
fn blink_cached(cache: &mut HashMap<(i64, i32), i64>, stone: i64, counter: i32) -> i64 {
if counter == 0 {
return 1;
}
let key = (stone, counter);
if let Some(result) = cache.get(&key) {
return *result;
}
let next = counter - 1;
let result = if stone == 0 {
blink_cached(cache, 1, next)
} else if let Some((left, right)) = split_stone(stone) {
blink_cached(cache, left, next) + blink_cached(cache, right, next)
} else {
blink_cached(cache, stone * 2024, next)
};
cache.insert(key, result);
result
}
fn part1(stones: &[i64]) -> i64 {
let mut total = 0;
for stone in stones.iter() {
total += blink(*stone, 25);
}
total
}
fn blink(stone: i64, counter: i32) -> i64 {
if counter == 0 {
return 1;
}
let next = counter - 1;
if stone == 0 {
blink(1, next)
} else if let Some((left, right)) = split_stone(stone) {
blink(left, next) + blink(right, next)
} else {
blink(stone * 2024, next)
}
}
fn split_stone(stone: i64) -> Option<(i64, i64)> {
let mut mask = 10;
let mut n_digits = 1;
while stone >= mask {
mask *= 10;
n_digits += 1;
}
if n_digits % 2 == 0 {
let half_n = n_digits / 2;
let mut half_mask = 1;
for _ in 0..half_n {
half_mask *= 10;
}
let left = stone / half_mask;
let right = stone % half_mask;
Some((left, right))
} else {
None
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment