retroactive, to derust my rust

fix day7 part2

+48 -83
+16
Cargo.lock
··· 15 15 name = "aoc2024" 16 16 version = "0.1.0" 17 17 dependencies = [ 18 + "itertools", 18 19 "regex", 20 + ] 21 + 22 + [[package]] 23 + name = "either" 24 + version = "1.15.0" 25 + source = "registry+https://github.com/rust-lang/crates.io-index" 26 + checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" 27 + 28 + [[package]] 29 + name = "itertools" 30 + version = "0.14.0" 31 + source = "registry+https://github.com/rust-lang/crates.io-index" 32 + checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" 33 + dependencies = [ 34 + "either", 19 35 ] 20 36 21 37 [[package]]
+1
Cargo.toml
··· 4 4 edition = "2024" 5 5 6 6 [dependencies] 7 + itertools = "0.14.0" 7 8 regex = "1.12.2"
+25 -78
src/day7.rs
··· 1 + use itertools::Itertools; 2 + 1 3 pub fn day7_part1(input: &str) -> String { 2 4 let input = parse(input); 3 5 let sum: u64 = input ··· 18 20 sum.to_string() 19 21 } 20 22 21 - fn possible_with_concatenation(res: u64, operands: &[u64]) -> bool { 23 + fn possible(result: u64, operands: &[u64]) -> bool { 22 24 let operator_count = operands.len() - 1; 23 - let possibilities = 0..(3u64.pow(operator_count as u32)); 24 - for possibility in possibilities { 25 - if evaluate_with_concatenation(possibility, operands) == res { 26 - return true; 27 - } 28 - } 29 - dbg!(res); 30 - false 25 + (0..operator_count) 26 + .map(|_| [Operator::Plus, Operator::Times]) 27 + .multi_cartesian_product() 28 + .any(|operators| check(result, operands, operators.as_slice())) 31 29 } 32 30 33 - fn evaluate_with_concatenation(mut bitpattern: u64, operands: &[u64]) -> u64 { 34 - // dbg!(bitpattern, operands); 35 - let selected_option = bitpattern % 3; 36 - let mut result = if selected_option == 0 { 37 - operands[0] + operands[1] 38 - } else if selected_option == 1 { 39 - operands[0] * operands[1] 40 - } else { 41 - concatenate(operands[0], operands[1]) 42 - }; 43 - 44 - let mut debug_operators = vec![]; 45 - 46 - for operator in 2..operands.len() { 47 - bitpattern /= 3; 48 - let selected_option = bitpattern % 3; 31 + fn possible_with_concatenation(result: u64, operands: &[u64]) -> bool { 32 + let operator_count = operands.len() - 1; 33 + (0..operator_count) 34 + .map(|_| [Operator::Plus, Operator::Times, Operator::Concatenate]) 35 + .multi_cartesian_product() 36 + .any(|operators| check(result, operands, operators.as_slice())) 37 + } 49 38 50 - result = if selected_option == 0 { 51 - result + operands[operator] 52 - } else if selected_option == 1 { 53 - result * operands[operator] 54 - } else { 55 - concatenate(result, operands[operator]) 56 - }; 57 - 58 - debug_operators.push(if selected_option == 0 { 59 - '+' 60 - } else if selected_option == 1 { 61 - '*' 62 - } else { 63 - '|' 64 - }); 39 + fn check(result: u64, operands: &[u64], operators: &[Operator]) -> bool { 40 + let mut accumulator = operands[0]; 41 + for (operator, operand) in operators.iter().zip(&operands[1..]) { 42 + match operator { 43 + Operator::Times => accumulator *= operand, 44 + Operator::Plus => accumulator += operand, 45 + Operator::Concatenate => accumulator = concatenate(accumulator, *operand), 46 + } 65 47 } 66 - 67 - // dbg!(result, bitpattern, debug_operators); 68 - result 48 + result == accumulator 69 49 } 70 50 71 51 fn concatenate(left: u64, right: u64) -> u64 { 72 - let decimal_places_shift = (right as f64).log10().ceil() as u32; 52 + let decimal_places_shift = right.ilog10() + 1; 73 53 left * 10u64.pow(decimal_places_shift) + right 74 54 } 75 55 ··· 78 58 assert_eq!(concatenate(15, 6), 156) 79 59 } 80 60 81 - fn possible(res: u64, operands: &[u64]) -> bool { 82 - // dbg!(res, operands); 83 - let operator_count = operands.len() - 1; 84 - let possibilities = 0..(2u64.pow(operator_count as u32)); 85 - for possibility in possibilities { 86 - if evaluate(possibility, operands) == res { 87 - return true; 88 - } 89 - } 90 - 91 - false 92 - } 93 - 94 - fn evaluate(bitpattern: u64, operands: &[u64]) -> u64 { 95 - // dbg!(bitpattern, operands); 96 - let mut result = if bitpattern & 0b1 == 0 { 97 - operands[0] + operands[1] 98 - } else { 99 - operands[0] * operands[1] 100 - }; 101 - 102 - for operator in 2..operands.len() { 103 - let multiply = bitpattern & (0b1 << (operator - 1)) != 0; 104 - if multiply { 105 - result *= operands[operator]; 106 - } else { 107 - result += operands[operator]; 108 - } 109 - } 110 - 111 - // dbg!(result); 112 - result 113 - } 114 - 115 61 #[derive(Copy, Clone, Eq, PartialEq, Debug)] 116 62 enum Operator { 117 63 Times, 118 64 Plus, 65 + Concatenate, 119 66 } 120 67 121 68 fn parse(input: &str) -> Vec<(u64, Vec<u64>)> {
+6 -5
src/lib.rs
··· 356 356 assert_eq!(result, "3598800864292"); 357 357 } 358 358 359 - // #[ignore] 359 + #[ignore] 360 360 #[test] 361 361 fn day7_part2_test() { 362 - // let simple_result = day7::day7_part2(include_str!("../input/day7_custom.test.txt")); 363 - // assert_eq!(simple_result, (12345 + 12034050 + 15 + 120).to_string()); 362 + let simple_result = day7::day7_part2(include_str!("../input/day7_custom.test.txt")); 363 + assert_eq!(simple_result, (12345 + 12034050 + 15 + 120).to_string()); 364 364 365 - // let test_result = day7::day7_part2(include_str!("../input/day7.test.txt")); 366 - // assert_eq!(test_result, "11387"); 365 + let test_result = day7::day7_part2(include_str!("../input/day7.test.txt")); 366 + assert_eq!(test_result, "11387"); 367 367 let result = day7::day7_part2(include_str!("../input/day7.txt")); 368 368 let parsed_result: u64 = result.parse::<u64>().unwrap(); 369 369 assert!(parsed_result > 318_910_516_761_637, "{parsed_result} was too low"); 370 + assert_eq!(parsed_result, 340_362_529_351_427); 370 371 } 371 372 372 373 #[test]