Advent of Code solutions in Rust

refactor: break out extension trait for set ops on ranges

+72 -46
+17 -46
aoc_2022/src/day15.rs
··· 1 1 use aoc_companion::prelude::*; 2 2 use aoc_utils::linalg::Vector; 3 3 4 + use aoc_utils::range::RangeSet; 4 5 use itertools::Itertools; 5 6 use tap::Tap; 6 7 use thiserror::Error; ··· 89 90 } 90 91 91 92 #[derive(Debug, PartialEq, Eq)] 92 - struct Coverage<C: Covering> { 93 + struct Coverage<C: RangeSet> { 93 94 positive: Vec<C>, 94 95 negative: Vec<C>, 95 96 } 96 97 97 - impl<C: Covering> Coverage<C> { 98 + impl<C> Coverage<C> 99 + where 100 + C: RangeSet + Iterator + Clone, 101 + { 98 102 fn new() -> Self { 99 103 Self { 100 104 positive: Vec::new(), ··· 106 110 let pos_intersections: Vec<_> = self 107 111 .positive 108 112 .iter() 109 - .flat_map(|p| p.intersect(&new)) 113 + .flat_map(|p| p.intersection(&new)) 110 114 .collect(); 111 115 let neg_intersections: Vec<_> = self 112 116 .negative 113 117 .iter() 114 - .flat_map(|p| p.intersect(&new)) 118 + .flat_map(|p| p.intersection(&new)) 115 119 .collect(); 116 120 self.positive.push(new); 117 121 self.negative.extend(pos_intersections); ··· 119 123 } 120 124 121 125 fn size(&self) -> usize { 122 - self.positive.iter().map(Covering::size).sum::<usize>() 123 - - self.negative.iter().map(Covering::size).sum::<usize>() 124 - } 125 - } 126 - 127 - trait Covering: Sized { 128 - fn intersect(&self, other: &Self) -> Option<Self>; 129 - fn size(&self) -> usize; 130 - } 131 - 132 - impl Covering for RangeInclusive<isize> { 133 - fn intersect(&self, other: &Self) -> Option<Self> { 134 - let range = (*self.start().max(other.start()))..=(*self.end().min(other.end())); 135 - (!range.is_empty()).then_some(range) 136 - } 137 - 138 - fn size(&self) -> usize { 139 - if self.is_empty() { 140 - 0 141 - } else { 142 - (self.end() + 1 - self.start()) as usize 143 - } 126 + self.positive 127 + .iter() 128 + .map(|c| c.clone().count()) 129 + .sum::<usize>() 130 + - self 131 + .negative 132 + .iter() 133 + .map(|c| c.clone().count()) 134 + .sum::<usize>() 144 135 } 145 136 } 146 137 ··· 268 259 assert!(SENSOR.line_covering(-3).is_empty()); 269 260 assert!(SENSOR.line_covering(17).is_empty()); 270 261 assert!(SENSOR.line_covering(20).is_empty()); 271 - } 272 - 273 - // 1 2 3 4 5 6 7 8 274 - // --------- 275 - // ----------- 276 - 277 - #[test] 278 - fn intersection_of_line_segments() { 279 - assert_eq!(Covering::intersect(&(1..=5), &(3..=8)), Some(3..=5)); 280 - assert_eq!(Covering::intersect(&(1..=8), &(3..=5)), Some(3..=5)); 281 - assert_eq!(Covering::intersect(&(1..=3), &(5..=8)), None); 282 - } 283 - 284 - #[test] 285 - #[allow(clippy::reversed_empty_ranges)] 286 - fn size_of_line_segments() { 287 - assert_eq!((1..=5).size(), 5); 288 - assert_eq!((3..=5).size(), 3); 289 - assert_eq!((5..=3).size(), 0); 290 - assert_eq!((3..=3).size(), 1); 291 262 } 292 263 293 264 #[test]
+1
aoc_utils/src/lib.rs
··· 3 3 pub mod geometry; 4 4 pub mod iter; 5 5 pub mod linalg; 6 + pub mod range; 6 7 pub mod wrap;
+54
aoc_utils/src/range.rs
··· 1 + use std::ops::RangeInclusive; 2 + 3 + /// Extension trait for set operations on range types 4 + pub trait RangeSet: Sized { 5 + fn intersection(&self, other: &Self) -> Option<Self>; 6 + } 7 + 8 + impl<T> RangeSet for RangeInclusive<T> 9 + where 10 + T: Copy + PartialOrd + Ord, 11 + { 12 + fn intersection(&self, other: &Self) -> Option<Self> { 13 + let range = (*self.start().max(other.start()))..=(*self.end().min(other.end())); 14 + (!range.is_empty()).then_some(range) 15 + } 16 + } 17 + 18 + #[cfg(test)] 19 + mod tests { 20 + use super::*; 21 + 22 + #[test] 23 + fn inclusive_range_intersection() { 24 + // 1 2 3 4 5 6 7 8 25 + // --------- 26 + // ----------- 27 + assert_eq!(RangeSet::intersection(&(1..=5), &(3..=8)), Some(3..=5)); 28 + 29 + // 1 2 3 4 5 6 7 8 30 + // ----------- 31 + // --------- 32 + assert_eq!(RangeSet::intersection(&(3..=8), &(1..=5)), Some(3..=5)); 33 + 34 + // 1 2 3 4 5 6 7 8 35 + // --------------- 36 + // ----- 37 + assert_eq!(RangeSet::intersection(&(1..=8), &(3..=5)), Some(3..=5)); 38 + 39 + // 1 2 3 4 5 6 7 8 40 + // ----- 41 + // --------------- 42 + assert_eq!(RangeSet::intersection(&(3..=5), &(1..=8)), Some(3..=5)); 43 + 44 + // 1 2 3 4 5 6 7 8 45 + // ----- 46 + // ------- 47 + assert_eq!(RangeSet::intersection(&(1..=3), &(5..=8)), None); 48 + 49 + // 1 2 3 4 5 6 7 8 50 + // ------- 51 + // ----- 52 + assert_eq!(RangeSet::intersection(&(5..=8), &(1..=3)), None); 53 + } 54 + }