at main 268 lines 9.2 kB view raw
1pub mod day1 { 2 fn day1_preprocess(input: &str) -> Vec<i16> { 3 input 4 .lines() 5 .map(|line| { 6 ( 7 line.starts_with('L'), 8 line.chars() 9 .skip(1) 10 .collect::<String>() 11 .parse::<i16>() 12 .unwrap(), 13 ) 14 }) 15 .map(|(is_left, distance)| if is_left { -distance } else { distance }) 16 .collect() 17 } 18 pub fn day1_part1(input: &str) -> String { 19 let rotations = day1_preprocess(input); 20 let mut popcnt = 0; 21 let mut pointing_at = 50; 22 for rotation in rotations { 23 pointing_at += rotation; 24 pointing_at %= 100; 25 if pointing_at == 0 { 26 popcnt += 1; 27 } 28 } 29 popcnt.to_string() 30 } 31 pub fn day1_part2(input: &str) -> String { 32 let rotations = day1_preprocess(input); 33 let mut popcnt = 0; 34 let mut pointing_at = 50; 35 for mut rotation in rotations { 36 while rotation != 0 { 37 if rotation < 0 { 38 let distance = 39 rotation.max(-(if pointing_at != 0 { pointing_at } else { 100 })); 40 pointing_at += distance; 41 rotation -= distance; 42 } else if rotation > 0 { 43 let distance = rotation.min(100 - pointing_at); 44 pointing_at += distance; 45 rotation -= distance; 46 } 47 pointing_at %= 100; 48 if pointing_at < 0 { 49 pointing_at += 100; 50 } else if pointing_at == 0 { 51 popcnt += 1; 52 } 53 } 54 } 55 popcnt.to_string() 56 } 57} 58 59pub mod day2 { 60 use std::ops::RangeInclusive; 61 62 pub fn day2_part1(input: &str) -> String { 63 let ranges = parse(input); 64 let invalid = ranges 65 .into_iter() 66 .flatten() 67 .filter(|&id| !is_id_valid(id, true)); 68 let invalid_sum: u64 = invalid.sum(); 69 invalid_sum.to_string() 70 } 71 pub fn day2_part2(input: &str) -> String { 72 let ranges = parse(input); 73 let invalid = ranges 74 .into_iter() 75 .flatten() 76 .filter(|&id| !is_id_valid(id, false)); 77 let invalid_sum: u64 = invalid.sum(); 78 invalid_sum.to_string() 79 } 80 fn parse(input: &str) -> Vec<RangeInclusive<u64>> { 81 input 82 .split(',') 83 .map(|range| range.split_once('-').unwrap()) 84 .map(|(from, to)| from.parse().unwrap()..=to.parse().unwrap()) 85 .collect() 86 } 87 fn is_id_valid(id: u64, max_two_chunks: bool) -> bool { 88 let charnum = id.ilog10() as usize + 1; 89 for chunk_count in 2..=if max_two_chunks { 2 } else { charnum } { 90 if !charnum.is_multiple_of(chunk_count) { 91 continue; 92 } 93 let chunk_size = charnum / chunk_count; 94 let mut equal = true; 95 'chunking: for intra_chunk_index in 0..chunk_size { 96 let first_digit = index(id, intra_chunk_index); 97 for inter_chunk_index in 1..chunk_count { 98 let digit_under_test = 99 index(id, inter_chunk_index * chunk_size + intra_chunk_index); 100 if digit_under_test != first_digit { 101 equal = false; 102 break 'chunking; 103 } 104 } 105 } 106 if equal { 107 return false; 108 } 109 } 110 true 111 } 112 #[inline] 113 fn index(id: u64, index: usize) -> u64 { 114 (id / 10u64.pow(index as u32)) % 10 115 } 116} 117 118pub mod day3; 119pub mod day4; 120pub mod day5; 121pub mod day6; 122pub mod day7; 123pub mod day8; 124pub mod day9; 125mod spatial; 126mod union_find; 127 128#[cfg(test)] 129mod tests { 130 use super::*; 131 132 #[test] 133 fn day9_part1_test() { 134 let test_result = day9::day9_part1(include_str!("../input/day9.test.txt")); 135 assert_eq!(test_result, "50"); 136 let result = day9::day9_part1(include_str!("../input/day9.txt")); 137 assert_eq!(result, "4760959496"); 138 } 139 #[test] 140 fn day9_part2_test() { 141 let test_result = day9::day9_part2(include_str!("../input/day9.test.txt")); 142 assert_eq!(test_result, "24"); 143 let result = day9::day9_part2(include_str!("../input/day9.txt")); 144 assert_eq!(result, "1343576598"); 145 } 146 147 148 #[test] 149 fn day8_part1_test() { 150 let test_result = day8::day8_part1(include_str!("../input/day8.test.txt"), 10); 151 assert_eq!(test_result, "40"); 152 let result = day8::day8_part1(include_str!("../input/day8.txt"), 1000); 153 assert_eq!(result, "90036"); 154 } 155 #[test] 156 fn day8_part2_test() { 157 let test_result = day8::day8_part2(include_str!("../input/day8.test.txt"), 1_000_000); 158 assert_eq!(test_result, "25272"); 159 let result = day8::day8_part2(include_str!("../input/day8.txt"), 1_000_000); 160 assert_eq!(result, "6083499488"); 161 } 162 163 #[test] 164 fn day7_part1_test() { 165 let test_result = day7::day7_part1(include_str!("../input/day7.test.txt")); 166 assert_eq!(test_result, "21"); 167 let result = day7::day7_part1(include_str!("../input/day7.txt")); 168 assert_eq!(result, "1490"); 169 } 170 #[test] 171 fn day7_part2_test() { 172 let test_result = day7::day7_part2(include_str!("../input/day7.test.txt")); 173 assert_eq!(test_result, "40"); 174 let result = day7::day7_part2(include_str!("../input/day7.txt")); 175 assert_eq!(result, "3806264447357"); 176 } 177 178 #[test] 179 fn day6_part1_test() { 180 let test_result = day6::day6_part1(include_str!("../input/day6.test.txt")); 181 assert_eq!(test_result, "4277556"); 182 let result = day6::day6_part1(include_str!("../input/day6.txt")); 183 assert_eq!(result, "4951502530386"); 184 } 185 #[test] 186 fn day6_part2_test() { 187 let test_result = day6::day6_part2(include_str!("../input/day6.test.txt")); 188 assert_eq!(test_result, "3263827"); 189 let result = day6::day6_part2(include_str!("../input/day6.txt")); 190 assert_eq!(result, "8486156119946"); 191 } 192 193 #[test] 194 fn day5_part1_test() { 195 let test_result = day5::day5_part1(include_str!("../input/day5.test.txt")); 196 assert_eq!(test_result, "3"); 197 let result = day5::day5_part1(include_str!("../input/day5.txt")); 198 assert_eq!(result, "885"); 199 } 200 #[test] 201 fn day5_part2_test() { 202 let test_result = day5::day5_part2(include_str!("../input/day5.test.txt")); 203 assert_eq!(test_result, "14"); 204 let result = day5::day5_part2(include_str!("../input/day5.txt")); 205 assert_eq!(result, "348115621205535"); 206 } 207 208 #[test] 209 fn day4_part1_test() { 210 let test_result = day4::day4_part1(include_str!("../input/day4.test.txt")); 211 assert_eq!(test_result, "13"); 212 let result = day4::day4_part1(include_str!("../input/day4.txt")); 213 assert_eq!(result, "1372"); 214 } 215 #[test] 216 fn day4_part2_test() { 217 let test_result = day4::day4_part2(include_str!("../input/day4.test.txt")); 218 assert_eq!(test_result, "43"); 219 let result = day4::day4_part2(include_str!("../input/day4.txt")); 220 assert_eq!(result, "7922"); 221 } 222 223 #[test] 224 fn day3_part1_test() { 225 let test_result = day3::day3_part1(include_str!("../input/day3.test.txt")); 226 assert_eq!(test_result, "357"); 227 let result = day3::day3_part1(include_str!("../input/day3.txt")); 228 assert_eq!(result, "17613"); 229 } 230 #[test] 231 fn day3_part2_test() { 232 let test_result = day3::day3_part2(include_str!("../input/day3.test.txt")); 233 assert_eq!(test_result, "3121910778619"); 234 let result = day3::day3_part2(include_str!("../input/day3.txt")); 235 assert_eq!(result, "175304218462560"); 236 } 237 238 #[test] 239 fn day2_part1_test() { 240 let test_result = day2::day2_part1(include_str!("../input/day2.test.txt")); 241 assert_eq!(test_result, "1227775554"); 242 let result = day2::day2_part1(include_str!("../input/day2.txt")); 243 assert_eq!(result, "38158151648"); 244 } 245 #[test] 246 fn day2_part2_test() { 247 let test_result = day2::day2_part2(include_str!("../input/day2.test.txt")); 248 assert_eq!(test_result, "4174379265"); 249 let result = day2::day2_part2(include_str!("../input/day2.txt")); 250 assert_eq!(result, "45283684555"); 251 } 252 253 #[test] 254 fn day1_part1_test() { 255 let test_result = day1::day1_part1(include_str!("../input/day1.test.txt")); 256 assert_eq!(test_result, "3"); 257 let result = day1::day1_part1(include_str!("../input/day1.txt")); 258 assert_eq!(result, "1021"); 259 } 260 261 #[test] 262 fn day1_part2_test() { 263 let test_result = day1::day1_part2(include_str!("../input/day1.test.txt")); 264 assert_eq!(test_result, "6"); 265 let result = day1::day1_part2(include_str!("../input/day1.txt")); 266 assert_eq!(result, "5933"); 267 } 268}