use std::{
collections::HashMap,
fs::File,
io::{BufRead, BufReader},
path::Path,
};
pub fn solve(input: &Path) -> anyhow::Result<()> {
println!("part one: {}", part_one(input)?);
println!("part two: {}", part_two(input)?);
Ok(())
}
fn part_one(input: &Path) -> anyhow::Result<usize> {
let mut reader = BufReader::new(File::open(input)?);
let mut input_str = String::new();
let _ = reader.read_line(&mut input_str)?;
let mut stones: Vec<Vec<usize>> = input_str
.split_whitespace()
.map(|c| -> Vec<usize> { vec![c.to_string().parse().unwrap()] })
.collect();
for _ in 0..25 {
for stone in &mut stones {
if stone[0] == 0 {
stone[0] = 1;
continue;
}
let stone_str = stone[0].to_string();
if stone_str.len() % 2 == 0 {
let (right, left) = stone_str.split_at(stone_str.len() / 2);
*stone = vec![right.parse()?, left.parse()?];
} else {
stone[0] *= 2024;
}
}
stones = stones
.iter()
.flatten()
.map(|stone| -> Vec<usize> { vec![*stone] })
.collect();
}
Ok(stones.iter().flatten().count())
}
fn part_two(input: &Path) -> anyhow::Result<usize> {
let mut reader = BufReader::new(File::open(input)?);
let mut input_str = String::new();
let _ = reader.read_line(&mut input_str)?;
let input_stones: Vec<usize> = input_str
.split_whitespace()
.map(|c| -> usize { c.to_string().parse().unwrap() })
.collect();
let mut stones: HashMap<usize, usize> = HashMap::new();
for stone in input_stones {
if let Some(amount) = stones.get_mut(&stone) {
*amount += 1;
} else {
stones.insert(stone, 1);
}
}
for _ in 0..75 {
for (stone, amount) in &stones.clone() {
*stones.entry(*stone).or_insert(0) -= amount;
if *stone == 0 {
*stones.entry(1).or_insert(0) += amount;
continue;
}
let stone_str = stone.to_string();
if stone_str.len() % 2 == 0 {
let (right, left) = stone_str.split_at(stone_str.len() / 2);
let right = right.parse()?;
let left = left.parse()?;
*stones.entry(right).or_insert(0) += amount;
*stones.entry(left).or_insert(0) += amount;
} else {
let new = stone * 2024;
*stones.entry(new).or_insert(0) += amount;
}
}
}
Ok(stones.values().sum())
}