Advent of Code solutions

Add num utils, clean up day 11

bwc9876.dev 56ee21ce 1e6757ea

verified
+99 -84
+2
utils/src/lib.rs
··· 4 4 pub mod grid; 5 5 pub mod line; 6 6 pub mod misc; 7 + pub mod num; 7 8 pub mod pos; 8 9 pub mod range; 9 10 ··· 16 17 pub use crate::grid::*; 17 18 pub use crate::line::*; 18 19 pub use crate::misc::*; 20 + pub use crate::num::*; 19 21 pub use crate::pos::*; 20 22 pub use crate::range::*; 21 23 }
+66
utils/src/num.rs
··· 1 + /// Gets the number of digits in a given number mathematically 2 + /// 3 + /// # Examples 4 + /// 5 + /// ``` 6 + /// use utils::prelude::*; 7 + /// 8 + /// let my_num = 2226; 9 + /// assert_eq!(num_digits(my_num), 4); 10 + /// ``` 11 + /// 12 + /// ``` 13 + /// use utils::prelude::*; 14 + /// 15 + /// let my_num = 120938747; 16 + /// assert_eq!(num_digits(my_num), 9); 17 + /// ``` 18 + /// 19 + /// ``` 20 + /// use utils::prelude::*; 21 + /// 22 + /// assert_eq!(num_digits(0), 1); 23 + /// ``` 24 + /// 25 + pub fn num_digits(num: usize) -> usize { 26 + num.checked_ilog10().map(|x| x as usize).unwrap_or(0) + 1 27 + } 28 + 29 + /// Split a given number at a specific digit, this digit will be included in the right-hand side 30 + /// and excluded in the left. 31 + /// 32 + /// If the split is invalid, zero may be returnd on either side of the result. 33 + /// 34 + /// # Examples 35 + /// 36 + /// ``` 37 + /// use utils::prelude::*; 38 + /// 39 + /// let my_num = 123456; 40 + /// let (left, right) = split_num_at(my_num, 3); 41 + /// assert_eq!(left, 123); 42 + /// assert_eq!(right, 456); 43 + /// ``` 44 + /// 45 + pub fn split_num_at(num: usize, idx: u32) -> (usize, usize) { 46 + let div = 10_usize.pow(idx); 47 + (num / div, num % div) 48 + } 49 + 50 + /// Split the given number once in the middle, see [[split_num_at]] for caveats. 51 + /// 52 + /// # Examples 53 + /// 54 + /// ``` 55 + /// use utils::prelude::*; 56 + /// 57 + /// let my_num = 55556666; 58 + /// let (left, right) = split_num_once(my_num); 59 + /// assert_eq!(left, 5555); 60 + /// assert_eq!(right, 6666); 61 + /// ``` 62 + /// 63 + pub fn split_num_once(num: usize) -> (usize, usize) { 64 + let digits = num_digits(num); 65 + split_num_at(num, (digits / 2) as u32) 66 + }
+31 -84
years/2024/src/day_11.rs
··· 1 1 use std::collections::HashMap; 2 2 3 3 use advent_core::{day_stuff, ex_for_day, Day}; 4 + use utils::num::{num_digits, split_num_once}; 4 5 5 6 pub struct Day11; 6 7 7 - impl Day for Day11 { 8 - day_stuff!(11, "55312", "65601038650482", Vec<u128>); 8 + fn do_blinks(stones: Vec<usize>, blinks: usize) -> usize { 9 + let l = stones.len(); 10 + let mut stone_map = stones 11 + .into_iter() 12 + .fold(HashMap::with_capacity(l), |mut acc, stone| { 13 + acc.entry(stone).and_modify(|c| *c += 1).or_insert(1); 14 + acc 15 + }); 9 16 10 - fn part_1(input: Self::Input) -> Option<String> { 11 - let l = input.len(); 12 - let mut stone_map = input 13 - .into_iter() 14 - .fold(HashMap::with_capacity(l), |mut acc, stone| { 15 - acc.entry(stone).and_modify(|c| *c += 1).or_insert(1); 16 - acc 17 - }); 17 + for _i in 0..blinks { 18 + let mut new_map = HashMap::with_capacity(stone_map.len() * 2); 18 19 19 - for _i in 0..25 { 20 - let mut new_map = HashMap::with_capacity(stone_map.len()); 21 - 22 - for (num, count) in stone_map { 23 - if num == 0 { 24 - new_map 25 - .entry(1) 26 - .and_modify(|c| *c += count) 27 - .or_insert(count); 20 + for (num, count) in stone_map { 21 + if num == 0 { 22 + *new_map.entry(1).or_insert(0) += count; 23 + } else { 24 + if num_digits(num) % 2 == 0 { 25 + let (left, right) = split_num_once(num); 26 + *new_map.entry(left).or_insert(0) += count; 27 + *new_map.entry(right).or_insert(0) += count; 28 28 } else { 29 - let ss = num.to_string(); 30 - let l = ss.len(); 31 - if l % 2 == 0 { 32 - let (num1, num2) = 33 - (ss[..l / 2].parse().unwrap(), ss[l / 2..].parse().unwrap()); 34 - new_map 35 - .entry(num1) 36 - .and_modify(|c| *c += count) 37 - .or_insert(count); 38 - new_map 39 - .entry(num2) 40 - .and_modify(|c| *c += count) 41 - .or_insert(count); 42 - } else { 43 - new_map 44 - .entry(num * 2024) 45 - .and_modify(|c| *c += count) 46 - .or_insert(count); 47 - } 29 + *new_map.entry(num * 2024).or_insert(0) += count; 48 30 } 49 31 } 50 - 51 - stone_map = new_map; 52 32 } 53 33 54 - Some(stone_map.values().sum::<u128>().to_string()) 34 + stone_map = new_map; 55 35 } 56 36 57 - fn part_2(input: Self::Input) -> Option<String> { 58 - let l = input.len(); 59 - let mut stone_map = input 60 - .into_iter() 61 - .fold(HashMap::with_capacity(l), |mut acc, stone| { 62 - acc.entry(stone).and_modify(|c| *c += 1).or_insert(1); 63 - acc 64 - }); 37 + stone_map.into_values().sum::<usize>() 38 + } 65 39 66 - for _i in 0..75 { 67 - let mut new_map = HashMap::with_capacity(stone_map.len()); 40 + impl Day for Day11 { 41 + day_stuff!(11, "55312", "65601038650482", Vec<usize>); 68 42 69 - for (num, count) in stone_map { 70 - if num == 0 { 71 - new_map 72 - .entry(1) 73 - .and_modify(|c| *c += count) 74 - .or_insert(count); 75 - } else { 76 - let ss = num.to_string(); 77 - let l = ss.len(); 78 - if l % 2 == 0 { 79 - let (num1, num2) = 80 - (ss[..l / 2].parse().unwrap(), ss[l / 2..].parse().unwrap()); 81 - new_map 82 - .entry(num1) 83 - .and_modify(|c| *c += count) 84 - .or_insert(count); 85 - new_map 86 - .entry(num2) 87 - .and_modify(|c| *c += count) 88 - .or_insert(count); 89 - } else { 90 - new_map 91 - .entry(num * 2024) 92 - .and_modify(|c| *c += count) 93 - .or_insert(count); 94 - } 95 - } 96 - } 43 + fn part_1(input: Self::Input) -> Option<String> { 44 + Some(do_blinks(input, 25).to_string()) 45 + } 97 46 98 - stone_map = new_map; 99 - } 100 - 101 - Some(stone_map.values().sum::<u128>().to_string()) 47 + fn part_2(input: Self::Input) -> Option<String> { 48 + Some(do_blinks(input, 75).to_string()) 102 49 } 103 50 104 51 fn parse_input(input: &str) -> Self::Input { 105 52 input 106 53 .trim() 107 54 .split(" ") 108 - .map(|n| n.parse::<u128>().unwrap()) 55 + .map(|n| n.parse::<usize>().unwrap()) 109 56 .collect() 110 57 } 111 58 }