retroactive, to derust my rust
at main 531 lines 17 kB view raw
1pub fn day1_preprocess(input: &str) -> (Vec<u32>, Vec<u32>) { 2 let pairs: Vec<Vec<u32>> = input 3 .lines() 4 .map(|line| { 5 line.split_ascii_whitespace() 6 .map(|location_id| location_id.parse().unwrap()) 7 .collect() 8 }) 9 .collect(); 10 11 let mut left = pairs.iter().map(|pair| pair[0]).collect::<Vec<_>>(); 12 let mut right = pairs.iter().map(|pair| pair[1]).collect::<Vec<_>>(); 13 left.sort(); 14 right.sort(); 15 (left, right) 16} 17pub fn day1_part1(input: &str) -> String { 18 let (left, right) = day1_preprocess(input); 19 let sum: u32 = left 20 .iter() 21 .zip(right) 22 .map(|(left, right)| left.abs_diff(right)) 23 .sum(); 24 sum.to_string() 25} 26 27pub fn day1_part2(input: &str) -> String { 28 let (left, right) = day1_preprocess(input); 29 let similarity_score: u32 = left 30 .into_iter() 31 .map(|left_location| { 32 left_location 33 * right 34 .iter() 35 .filter(|&&right_location| right_location == left_location) 36 .count() as u32 37 }) 38 .sum(); 39 similarity_score.to_string() 40} 41 42pub mod day2 { 43 fn day2_preprocess(input: &str) -> Vec<Vec<u32>> { 44 input 45 .lines() 46 .map(|report| { 47 report 48 .split_ascii_whitespace() 49 .map(|level| level.parse().unwrap()) 50 .collect() 51 }) 52 .collect() 53 } 54 pub fn day2_part1(input: &str) -> String { 55 let reports = day2_preprocess(input); 56 reports 57 .into_iter() 58 .filter(gradual) 59 .filter(monotonic) 60 .count() 61 .to_string() 62 } 63 pub fn day2_part2(input: &str) -> String { 64 let reports = day2_preprocess(input); 65 reports 66 .into_iter() 67 .filter(should_filter_out_part2) 68 .count() 69 .to_string() 70 } 71 fn should_filter_out_part2(report: &Vec<u32>) -> bool { 72 if gradual(report) && monotonic(report) { 73 return true; 74 } 75 for index_to_skip in 0..report.len() { 76 let skipped_report: Vec<u32> = report 77 .iter() 78 .enumerate() 79 .filter(|(i, _)| *i != index_to_skip) 80 .map(|(_, elem)| *elem) 81 .collect(); 82 if gradual(&skipped_report) && monotonic(&skipped_report) { 83 return true; 84 } 85 } 86 false 87 } 88 89 fn gradual(report: &Vec<u32>) -> bool { 90 for i in 1..report.len() { 91 let diff = report[i].abs_diff(report[i - 1]); 92 if !(1..=3).contains(&diff) { 93 return false; 94 } 95 } 96 true 97 } 98 99 //fails if not gradual 100 fn monotonic(report: &Vec<u32>) -> bool { 101 let increasing = report[0] < report[1]; 102 for i in 1..report.len() { 103 if increasing { 104 if report[i] < report[i - 1] { 105 return false; 106 } 107 } else if report[i] > report[i - 1] { 108 return false; 109 } 110 } 111 true 112 } 113} 114 115pub mod day3 { 116 use regex::Regex; 117 118 pub fn day3_part1(input: &str) -> String { 119 let r = Regex::new(r"mul\((\d+),(\d+)\)").unwrap(); 120 let multiplicands: Vec<(u32, u32)> = r 121 .captures_iter(input) 122 .map(|captures| { 123 dbg!(&captures); 124 (captures[1].parse().unwrap(), captures[2].parse().unwrap()) 125 }) 126 .collect(); 127 let products: u32 = multiplicands.into_iter().map(|(l, r)| l * r).sum(); 128 products.to_string() 129 } 130 131 pub fn day3_part2(input: &str) -> String { 132 let r = Regex::new(r"(?:do\(\))|(?:don't\(\))|(?:mul\((\d+),(\d+)\))").unwrap(); 133 let mut multiply = true; 134 let mut products: Vec<(u32, u32)> = vec![]; 135 for captures in r.captures_iter(input) { 136 dbg!(&captures); 137 if &captures[0] == "do()" { 138 multiply = true; 139 } else if &captures[0] == "don't()" { 140 multiply = false; 141 } else if multiply { 142 products.push((captures[1].parse().unwrap(), captures[2].parse().unwrap())); 143 } 144 } 145 let sum: u32 = products.into_iter().map(|(l, r)| l * r).sum(); 146 sum.to_string() 147 } 148} 149 150pub mod day4 { 151 use regex::Regex; 152 153 pub fn day4_part1(input: &str) -> String { 154 let pattern = Regex::new(r"XMAS").unwrap(); 155 let reverse_pattern = Regex::new(r"SAMX").unwrap(); 156 let mut count = 0; 157 158 count += pattern.find_iter(input).count(); 159 count += reverse_pattern.find_iter(input).count(); 160 dbg!(count); 161 162 let transposed = dbg!(transpose_string(input)); 163 164 count += pattern.find_iter(&transposed).count(); 165 count += reverse_pattern.find_iter(&transposed).count(); 166 167 dbg!(count); 168 let diag1 = dbg!(rotate_string_45degrees_counterclockwise(input)); 169 count += pattern.find_iter(&diag1).count(); 170 count += reverse_pattern.find_iter(&diag1).count(); 171 172 dbg!(count); 173 let diag2 = dbg!(rotate_string_45degrees_clockwise(input)); 174 count += pattern.find_iter(&diag2).count(); 175 count += reverse_pattern.find_iter(&diag2).count(); 176 177 dbg!(count); 178 count.to_string() 179 } 180 181 pub fn day4_part2(input: &str) -> String{ 182 let input = string_to_array(input); 183 let mut count = 0; 184 for row in 1..input.len()-1 { 185 for col in 1..input.len()-1 { 186 if is_x_mas(&input, row, col) { 187 count += 1; 188 } 189 } 190 } 191 count.to_string() 192 } 193 194 /* S&M combinations for X-MAS 195 MS 196 MS 197 198 SM 199 SM 200 201 MM 202 SS 203 204 SS 205 MM */ 206 //precondition: row and col are one away from the edge 207 fn is_x_mas(input: &Vec<Vec<char>>, row: usize, col: usize) -> bool { 208 if input[row][col] != 'A' { 209 return false; 210 } 211 if input[row-1][col-1] == 'M' { 212 if input[row-1][col+1] == 'M' { 213 input[row+1][col+1] == 'S' && input[row+1][col-1] == 'S' 214 } else if input[row+1][col-1] == 'M' { 215 input[row+1][col+1] == 'S' && input[row-1][col+1] == 'S' 216 } else { 217 false 218 } 219 } else if input[row-1][col-1] == 'S' { 220 if input[row-1][col+1] == 'S' { 221 input[row+1][col+1] == 'M' && input[row+1][col-1] == 'M' 222 } else if input[row+1][col-1] == 'S' { 223 input[row+1][col+1] == 'M' && input[row-1][col+1] == 'M' 224 } else { 225 false 226 } 227 } else { 228 false 229 } 230 231 } 232 233 //squares only 234 fn rotate_string_45degrees_counterclockwise(input: &str) -> String { 235 let array_input = string_to_array(input); 236 assert_eq!(array_input.len(), array_input[0].len()); 237 let mut array_output = vec![vec!['\0'; array_input.len()]; array_input.len() * 2 - 1]; 238 239 // [(0, 5)] 240 // [(0, 4), (1, 5)] 241 // [(0, 3), (1, 4), (2, 5)] 242 // [(0, 2), (1, 3), (2, 4), (3, 5)] 243 // [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)] 244 // [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)] 245 // [(1, 0), (2, 1), (3, 2), (4, 3), (5, 4)] 246 // [(2, 0), (3, 1), (4, 2), (5, 3)] 247 // [(3, 0), (4, 1), (5, 2)] 248 // [(4, 0), (5, 1)] 249 // [(5, 0)] 250 251 for input_row in 0..array_input.len() { 252 for input_col in 0..array_input.len() { 253 let output_row = (array_input.len() - 1) as isize + (input_row as isize - input_col as isize); 254 array_output[output_row as usize].push(array_input[input_row][input_col]); 255 } 256 } 257 258 let horistrings = array_output 259 .into_iter() 260 .map(|row| row.iter().filter(|&&c| c != '\0').collect::<String>()) 261 .collect::<Vec<_>>(); 262 horistrings.join("\n") 263 } 264 265 fn rotate_string_45degrees_clockwise(input: &str) -> String { 266 let mut unstrung = string_to_array(input); 267 flip_horizontal(&mut unstrung); 268 let restrung = horizontal_strings(&unstrung); 269 rotate_string_45degrees_counterclockwise(&restrung.join("\n")) 270 } 271 272 #[cfg(test)] 273 #[test] 274 fn string_rotation_tests() { 275 let square_string = "AB\nCD"; 276 let rotated = rotate_string_45degrees_counterclockwise(square_string); 277 // B 278 //A D 279 // C 280 assert_eq!(rotated, "B\nAD\nC"); 281 282 /* 283 ABCDE 284 FGHIJ 285 KLMNO 286 PQRST 287 UVWXY 288 289 rotated counterclockwise: 290 291 E 292 D J 293 C I O 294 B H N T 295 A G M S Y 296 F L R X 297 K Q W 298 P V 299 U 300 301 */ 302 303 let square_5x = "ABCDE\nFGHIJ\nKLMNO\nPQRST\nUVWXY"; 304 let rotated = rotate_string_45degrees_counterclockwise(square_5x); 305 day4_part1(square_5x); 306 dbg!(rotated); 307 // panic!() 308 } 309 310 fn transpose_string(input: &str) -> String { 311 let unstrung = string_to_array(input); 312 let transposed = transpose(&unstrung); 313 let horistrings = horizontal_strings(&transposed); 314 horistrings.join("\n") 315 } 316 317 fn string_to_array(input: &str) -> Vec<Vec<char>> { 318 input.lines().map(|line| line.chars().collect()).collect() 319 } 320 321 fn horizontal_strings(input: &Vec<Vec<char>>) -> Vec<String> { 322 input.iter().map(|row| row.iter().collect()).collect() 323 } 324 325 fn transpose(input: &Vec<Vec<char>>) -> Vec<Vec<char>> { 326 let mut output = vec![vec!['\0'; input.len()]; input[0].len()]; 327 328 for col in 0..input[0].len() { 329 for row in 0..input.len() { 330 output[col][row] = input[row][col] 331 } 332 } 333 output 334 } 335 336 fn flip_horizontal(input: &mut Vec<Vec<char>>) { 337 for row in 0..input.len() { 338 input[row].reverse() 339 } 340 } 341} 342 343pub mod day5; 344pub mod day6; 345pub mod day7; 346pub mod day8; 347pub mod day9; 348pub mod day10; 349pub mod spatial; 350 351#[cfg(test)] 352mod tests { 353 use super::*; 354 355 #[test] 356 fn day10_part1_test() { 357 let test_result = day10::day10_part1(include_str!("../input/day10.test.txt")); 358 assert_eq!(test_result, "36"); 359 let result = day10::day10_part1(include_str!("../input/day10.txt")); 360 assert_eq!(result, "820"); 361 } 362 #[test] 363 fn day10_part2_test() { 364 let test_result = day10::day10_part2(include_str!("../input/day10_simple2.test.txt")); 365 assert_eq!(test_result, "3"); 366 let test_result = day10::day10_part2(include_str!("../input/day10_simple.test.txt")); 367 assert_eq!(test_result, "13"); 368 let test_result = day10::day10_part2(include_str!("../input/day10.test.txt")); 369 assert_eq!(test_result, "81"); 370 let result = day10::day10_part2(include_str!("../input/day10.txt")); 371 assert_eq!(result, "1786"); 372 } 373 374 #[test] 375 fn day9_part1_test() { 376 let test_result = day9::day9_part1(include_str!("../input/day9.test.txt")); 377 assert_eq!(test_result, "1928"); 378 let result = day9::day9_part1(include_str!("../input/day9.txt")); 379 assert_eq!(result, "6448989155953"); 380 } 381 #[test] 382 fn day9_part2_test() { 383 let test_result = day9::day9_part2(include_str!("../input/day9.test.txt")); 384 assert_eq!(test_result, "2858"); 385 let result = day9::day9_part2(include_str!("../input/day9.txt")); 386 assert_eq!(result, "6476642796832"); 387 } 388 389 #[test] 390 fn day8_part1_test() { 391 let simple_result = day8::day8_part1(include_str!("../input/day8.simple.test.txt")); 392 assert_eq!(simple_result, "2"); 393 let simple2_result = day8::day8_part1(include_str!("../input/day8.simple2.test.txt")); 394 assert_eq!(simple2_result, "4"); 395 let test_result = day8::day8_part1(include_str!("../input/day8.test.txt")); 396 assert_eq!(test_result, "14"); 397 let result = day8::day8_part1(include_str!("../input/day8.txt")); 398 // assert!(result.parse::<u64>().unwrap() < 414); //too high 399 assert_eq!(result, "369"); 400 } 401 #[test] 402 fn day8_part2_test() { 403 let test_result = day8::day8_part2(include_str!("../input/day8.test.txt")); 404 assert_eq!(test_result, "34"); 405 let result = day8::day8_part2(include_str!("../input/day8.txt")); 406 assert_eq!(result, "1169"); 407 } 408 409 #[test] 410 fn day7_part1_test() { 411 let test_result = day7::day7_part1(include_str!("../input/day7.test.txt")); 412 assert_eq!(test_result, "3749"); 413 let result = day7::day7_part1(include_str!("../input/day7.txt")); 414 assert_eq!(result, "3598800864292"); 415 } 416 417 #[ignore] 418 #[test] 419 fn day7_part2_test() { 420 let simple_result = day7::day7_part2(include_str!("../input/day7_custom.test.txt")); 421 assert_eq!(simple_result, (12345 + 12034050 + 15 + 120).to_string()); 422 423 let test_result = day7::day7_part2(include_str!("../input/day7.test.txt")); 424 assert_eq!(test_result, "11387"); 425 let result = day7::day7_part2(include_str!("../input/day7.txt")); 426 let parsed_result: u64 = result.parse::<u64>().unwrap(); 427 assert!(parsed_result > 318_910_516_761_637, "{parsed_result} was too low"); 428 assert_eq!(parsed_result, 340_362_529_351_427); 429 } 430 431 #[test] 432 fn day6_part1_test() { 433 let test_result = day6::day6_part1(include_str!("../input/day6.test.txt")); 434 assert_eq!(test_result, "41"); 435 let result = day6::day6_part1(include_str!("../input/day6.txt")); 436 assert_eq!(result, "5131"); 437 } 438 439 #[ignore] 440 #[test] 441 fn day6_part2_test() { 442 let test_result = day6::day6_part2(include_str!("../input/day6.test.txt")); 443 assert_eq!(test_result, "6"); 444 let result = day6::day6_part2(include_str!("../input/day6.txt")); 445 assert_eq!(result, "1784"); 446 } 447 448 #[test] 449 fn day5_part1_test() { 450 let test_result = day5::day5_part1(include_str!("../input/day5.test.txt")); 451 assert_eq!(test_result, "143"); 452 let result = day5::day5_part1(include_str!("../input/day5.txt")); 453 assert_eq!(result, "5452"); 454 } 455 456 #[test] 457 fn day5_part2_test() { 458 let test_result = day5::day5_part2(include_str!("../input/day5.test.txt")); 459 assert_eq!(test_result, "123"); 460 let result = day5::day5_part2(include_str!("../input/day5.txt")); 461 assert_eq!(result, "4598"); 462 } 463 464 #[test] 465 fn day4_part1_test() { 466 let simplest = "..X...\n.SAMX.\n.A..A.\nXMAS.S\n.X....\n......"; 467 let test_result = day4::day4_part1(simplest); 468 assert_eq!(test_result, "4"); 469 470 let test_result = day4::day4_part1(include_str!("../input/day4.test.txt")); 471 assert_eq!(test_result, "18"); 472 let result = day4::day4_part1(include_str!("../input/day4.txt")); 473 assert_ne!(result, "2092"); //too low 474 assert_eq!(result, "2493"); 475 } 476 477 #[test] 478 fn day4_part2_test() { 479 let test_result = day4::day4_part2(include_str!("../input/day4.test.txt")); 480 assert_eq!(test_result, "9"); 481 let result = day4::day4_part2(include_str!("../input/day4.txt")); 482 assert_eq!(result, "1890"); 483 } 484 485 #[test] 486 fn day3_part1_test() { 487 let test_result = day3::day3_part1(include_str!("../input/day3.test.txt")); 488 assert_eq!(test_result, "161"); 489 let result = day3::day3_part1(include_str!("../input/day3.txt")); 490 assert_eq!(result, "183788984"); 491 } 492 493 #[test] 494 fn day3_part2_test() { 495 let test_result = day3::day3_part2(include_str!("../input/day3_part2.test.txt")); 496 assert_eq!(test_result, "48"); 497 let result = day3::day3_part2(include_str!("../input/day3.txt")); 498 assert_eq!(result, "62098619"); 499 } 500 501 #[test] 502 fn day2_part1_test() { 503 let test_result = day2::day2_part1(include_str!("../input/day2.test.txt")); 504 assert_eq!(test_result, "2"); 505 let result = day2::day2_part1(include_str!("../input/day2.txt")); 506 assert_eq!(result, "213"); 507 } 508 #[test] 509 fn day2_part2_test() { 510 let test_result = day2::day2_part2(include_str!("../input/day2.test.txt")); 511 assert_eq!(test_result, "4"); 512 let result = day2::day2_part2(include_str!("../input/day2.txt")); 513 assert_eq!(result, "285"); 514 } 515 516 #[test] 517 fn day1_part1_test() { 518 let test_result = day1_part1(include_str!("../input/day1_part1.test.txt")); 519 assert_eq!(test_result, "11"); 520 let result = day1_part1(include_str!("../input/day1.txt")); 521 assert_eq!(result, "2742123"); 522 } 523 524 #[test] 525 fn day1_part2_test() { 526 let test_result = day1_part2(include_str!("../input/day1_part1.test.txt")); 527 assert_eq!(test_result, "31"); 528 let result = day1_part2(include_str!("../input/day1.txt")); 529 assert_eq!(result, "21328497"); 530 } 531}