Advent of Code solutions in Rust

feat: part 2 of day 13 of AoC 2020

+138
+1
Cargo.lock
··· 98 98 "aoc_utils", 99 99 "itertools", 100 100 "ndarray", 101 + "num-integer", 101 102 "regex", 102 103 "thiserror", 103 104 "tokio",
+1
aoc_2020/Cargo.toml
··· 14 14 regex = { workspace = true } 15 15 thiserror = { workspace = true } 16 16 tokio = { workspace = true } 17 + num-integer = "0.1.46" 17 18
+134
aoc_2020/src/day13.rs
··· 27 27 earliest_departure(self.arrival_time, &self.bus_schedule) 28 28 .ok_or_else(|| anyhow!("no buses scheduled")) 29 29 } 30 + 31 + fn part2(&self) -> Result<i128> { 32 + earliest_alignment(&self.bus_schedule).ok_or_else(|| anyhow!("no buses scheduled")) 33 + } 30 34 } 31 35 32 36 enum BusLine { ··· 65 69 .map(|min_id| min_id * (min_id - arrival % min_id)) 66 70 } 67 71 72 + #[derive(Copy, Clone, Debug, PartialEq, Eq)] 73 + struct Orbit { 74 + period: i128, 75 + phase: i128, 76 + } 77 + 78 + fn combine_orbits(a: Orbit, b: Orbit) -> Orbit { 79 + use num_integer::ExtendedGcd; 80 + use num_integer::Integer as _; 81 + let (ExtendedGcd { gcd, x, y: _ }, lcm) = i128::extended_gcd_lcm(&a.period, &b.period); 82 + let (z, 0) = (a.phase - b.phase).div_rem(&gcd) else { 83 + panic!("orbits {a:?} and {b:?} never align"); 84 + }; 85 + Orbit { 86 + period: lcm, 87 + phase: (-z * x * a.period + a.phase).rem_euclid(lcm), 88 + } 89 + } 90 + 91 + fn earliest_alignment(schedule: &[BusLine]) -> Option<i128> { 92 + schedule 93 + .iter() 94 + .enumerate() 95 + .filter_map(|(idx, bus)| { 96 + Some(Orbit { 97 + period: bus.id()? as i128, 98 + phase: idx as i128, 99 + }) 100 + }) 101 + .reduce(combine_orbits) 102 + .map(|o| (-o.phase).rem_euclid(o.period)) 103 + } 104 + 68 105 #[cfg(test)] 69 106 mod tests { 70 107 use super::*; ··· 86 123 assert_eq!( 87 124 earliest_departure(EXAMPLE_ARRIVAL, &EXAMPLE_SCHEDULE), 88 125 Some(295) 126 + ); 127 + } 128 + 129 + #[test] 130 + fn combine_orbits_incrementally() { 131 + assert_eq!( 132 + combine_orbits( 133 + Orbit { 134 + period: 3, 135 + phase: 0 136 + }, 137 + Orbit { 138 + period: 4, 139 + phase: 1 140 + } 141 + ), 142 + Orbit { 143 + period: 12, 144 + phase: 9 // = (-3) % 12 145 + } 146 + ); 147 + assert_eq!( 148 + combine_orbits( 149 + Orbit { 150 + period: 12, 151 + phase: 9 152 + }, 153 + Orbit { 154 + period: 5, 155 + phase: 3 156 + } 157 + ), 158 + Orbit { 159 + period: 60, 160 + phase: 33 // = (-27) % 60 161 + } 162 + ); 163 + } 164 + 165 + #[test] 166 + fn find_earliest_alignment() { 167 + assert_eq!( 168 + earliest_alignment(&[ 169 + BusLine::BusId(3), 170 + BusLine::BusId(4), 171 + BusLine::Omission, 172 + BusLine::BusId(5), 173 + ]), 174 + Some(27) 175 + ); 176 + assert_eq!(earliest_alignment(&EXAMPLE_SCHEDULE), Some(1068781)); 177 + assert_eq!( 178 + earliest_alignment(&[ 179 + BusLine::BusId(17), 180 + BusLine::Omission, 181 + BusLine::BusId(13), 182 + BusLine::BusId(19), 183 + ]), 184 + Some(3417) 185 + ); 186 + assert_eq!( 187 + earliest_alignment(&[ 188 + BusLine::BusId(67), 189 + BusLine::BusId(7), 190 + BusLine::BusId(59), 191 + BusLine::BusId(61), 192 + ]), 193 + Some(754018) 194 + ); 195 + assert_eq!( 196 + earliest_alignment(&[ 197 + BusLine::BusId(67), 198 + BusLine::Omission, 199 + BusLine::BusId(7), 200 + BusLine::BusId(59), 201 + BusLine::BusId(61), 202 + ]), 203 + Some(779210) 204 + ); 205 + assert_eq!( 206 + earliest_alignment(&[ 207 + BusLine::BusId(67), 208 + BusLine::BusId(7), 209 + BusLine::Omission, 210 + BusLine::BusId(59), 211 + BusLine::BusId(61), 212 + ]), 213 + Some(1261476) 214 + ); 215 + assert_eq!( 216 + earliest_alignment(&[ 217 + BusLine::BusId(1789), 218 + BusLine::BusId(37), 219 + BusLine::BusId(47), 220 + BusLine::BusId(1889), 221 + ]), 222 + Some(1202161486) 89 223 ); 90 224 } 91 225 }
+2
aoc_companion/src/door.rs
··· 64 64 impl Submissible for i32 {} 65 65 impl Submissible for u64 {} 66 66 impl Submissible for i64 {} 67 + impl Submissible for u128 {} 68 + impl Submissible for i128 {} 67 69 impl Submissible for usize {} 68 70 impl Submissible for isize {} 69 71 impl Submissible for String {}