diff --git a/advent_of_code/2024/7/src/main.rs b/advent_of_code/2024/7/src/main.rs index 5c62372..b8eb6e9 100644 --- a/advent_of_code/2024/7/src/main.rs +++ b/advent_of_code/2024/7/src/main.rs @@ -1,69 +1,101 @@ use nom::{ bytes::complete::tag, - character::complete::{i32, multispace1}, + character::complete::{i64, multispace1}, multi::separated_list1, sequence::separated_pair, IResult, }; -fn parse(input: &str) -> IResult<&str, Vec<(i32, Vec)>> { +fn parse(input: &str) -> IResult<&str, Vec<(i64, Vec)>> { let (input, result) = separated_list1( multispace1, - separated_pair(i32, tag(": "), separated_list1(tag(" "), i32)), + separated_pair(i64, tag(": "), separated_list1(tag(" "), i64)), )(input)?; Ok((input, result)) } -fn check(original_target: i32, line: &[i32]) -> Option { - //dbg!(original_target, &line); - if line.iter().fold(1, |p, n| p * n) > original_target { +fn check(original_target: i64, line: &[i64]) -> Option { + let mut target = original_target; + + for (i, number) in line.iter().enumerate().rev() { + if i == 0 && target == *number { + return Some(original_target); + } + + if target % number == 0 { + if check(target - number, &line[..i]).is_some() { + return Some(original_target); + } + + target /= number; + } else { + target -= number; + } + } + + None +} + +fn solve_1(input: &str) -> i64 { + let (_, lines) = parse(input).unwrap(); + + lines.into_iter().fold(0, |result, line| { + check(line.0, &line.1[..]).unwrap_or_default() + result + }) +} + +fn check_2(original_target: i64, numbers: &[i64]) -> Option { + if let Some((i, number)) = numbers.iter().enumerate().rev().next() { + if i == 0 && original_target == *number { + return Some(original_target); + } + + if original_target % number == 0 { + if check_2(original_target / number, &numbers[..i]).is_some() { + return Some(original_target); + } + } + if original_target - number >= 0 { + if check_2(original_target - number, &numbers[..i]).is_some() { + return Some(original_target); + } + } + if let Some(head) = disconcat(original_target, *number) { + if check_2(head, &numbers[..i]).is_some() { + return Some(original_target); + } + } + } + + None +} + +fn disconcat(whole: i64, tail: i64) -> Option { + if tail > whole { return None; } - let mut target = original_target; - let mut i = line.len() as i32 - 1; + let mut whole_s = whole.to_string(); + let tail_s = tail.to_string(); - while i >= 0 { - let modulo = target % line[i as usize]; + let whole_split = whole_s.split_off(whole_s.len() - tail_s.len()); - if modulo == 0 { - target /= line[i as usize]; - - let plus_result = check(target - line[i as usize], &line[0..i as usize]); - - if plus_result.is_some() { - return plus_result; - } - } else { - target -= line[i as usize]; - } - - if target < 0 { - return None; - } - - i -= 1; - } - - if target == 0 { - Some(original_target) + if whole_split == tail_s { + Some(whole_s.parse().unwrap_or_default()) } else { None } } -fn solve_1(input: &str) -> i32 { +fn solve_2(input: &str) -> i64 { let (_, lines) = parse(input).unwrap(); - lines.into_iter().fold(0, |result, line| { - dbg!(&line); - result + check(line.0, &line.1[..]).unwrap_or_default() + lines.into_iter().fold(0, |result, (target, numbers)| { + check_2(target, &numbers[..]).unwrap_or_default() + result }) } -fn solve_2(input: &str) {} - fn main() { println!("Hello, this is Patrick!"); @@ -73,6 +105,7 @@ fn main() { println!("The total calibration result is {}", result_1); let result_2 = solve_2(input); + println!("The new total calibration result is {}", result_2); } #[cfg(test)] @@ -87,5 +120,8 @@ mod tests { } #[test] - fn test_2() {} + fn test_2() { + let test_input = include_str!("../test.txt"); + assert_eq!(solve_2(test_input), 11387); + } }