Advent of Code solutions
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///
25pub 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 returned 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///
45pub 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/// Get the digit at the (starting from the right) given index
51pub fn digit_at(num: usize, idx: usize) -> usize {
52 let div = 10_usize.pow(idx as u32);
53 num / div % 10
54}
55
56/// Iterator (from right to left)
57struct Digits {
58 num: usize,
59 size: usize,
60 curr_digit: usize,
61}
62
63impl Digits {
64 pub fn new(num: usize) -> Self {
65 Self {
66 num,
67 size: num_digits(num),
68 curr_digit: 0,
69 }
70 }
71}
72
73impl Iterator for Digits {
74 type Item = usize;
75
76 fn next(&mut self) -> Option<Self::Item> {
77 if self.curr_digit == self.size - 1 {
78 None
79 } else {
80 let res = Some(digit_at(self.num, self.curr_digit));
81 self.curr_digit += 1;
82 res
83 }
84 }
85}
86
87/// Split the given number once in the middle, see [[split_num_at]] for caveats.
88///
89/// # Examples
90///
91/// ```
92/// use utils::prelude::*;
93///
94/// let my_num = 55556666;
95/// let (left, right) = split_num_once(my_num);
96/// assert_eq!(left, 5555);
97/// assert_eq!(right, 6666);
98/// ```
99///
100pub fn split_num_once(num: usize) -> (usize, usize) {
101 let digits = num_digits(num);
102 split_num_at(num, (digits / 2) as u32)
103}