diff --git a/day-13/src/main.rs b/day-13/src/main.rs index 0a97ad2..be4bd15 100644 --- a/day-13/src/main.rs +++ b/day-13/src/main.rs @@ -9,7 +9,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { println!("{}", (arrival - time) * earliest); // Part 2 - let timestamp = find_incrementing(&ids); + let timestamp = find_gauss(&ids); println!("{}", timestamp); Ok(()) @@ -28,7 +28,7 @@ fn parse_notes(input: &str) -> Result<(u32, Vec<u32>), &str> { .next() .ok_or("Input too short")? .split(',') - .map(|id| id.parse().unwrap_or(0)) + .map(|id| id.parse().unwrap_or(1)) .collect(); Ok((estimate, ids)) @@ -36,7 +36,7 @@ fn parse_notes(input: &str) -> Result<(u32, Vec<u32>), &str> { fn find_closest_bus(time: u32, ids: &Vec<u32>) -> (u32, u32) { ids.iter() - .filter(|id| **id != 0) + .filter(|id| **id != 1) .map(|id| { let mut arrival = *id; @@ -50,48 +50,39 @@ fn find_closest_bus(time: u32, ids: &Vec<u32>) -> (u32, u32) { .expect("Must have at least one bus ID") } -fn find_incrementing(ids: &Vec<u32>) -> u128 { +fn find_gauss(ids: &Vec<u32>) -> u128 { let ids: Vec<u128> = ids.iter().map(|id| *id as u128).collect(); - let (largest, increment) = ids - .iter() - .enumerate() - .max_by_key(|id| id.1) - .expect("Must have at least one bus ID"); + let product: u128 = ids.iter().product(); - let mut iterations = (14166999999493 - largest as u128) / increment; + let gauss = |mut n: u128, mut d: u128, m: u128| -> u128 { + while d != 1 { + if m == 1 { + return 0; + }; - loop { - iterations += 1; - let max = increment * iterations; - - if ids.iter().enumerate().rev().all(|(i, number)| { - if *number == 0 { - true + let multiplier = if m > d { + m / d + (m % d != 0) as u128 } else { - let target = max - largest as u128 + i as u128; - target % number == 0 - } - }) { - break max - largest as u128; - } else { - if iterations % 100000000 == 0 { - let fun = ids - .iter() - .enumerate() - .filter(|(i, number)| { - if **number == 0 { - true - } else { - let target = max - largest as u128 + *i as u128; - target % **number == 0 - } - }) - .count(); + 1 + }; - println!("{} - {}/{}", max - largest as u128, fun, ids.len()); - } + n = (n * multiplier) % m; + d = (d * multiplier) % m; } - } + + n / d + }; + + (0..ids.len()) + .map(|a| { + let b = product / ids[a]; + let bi = gauss(1, b, ids[a]); + let a = (ids[a] * a as u128 - a as u128) % ids[a] as u128; + + a * b * bi + }) + .sum::<u128>() + % product } #[cfg(test)] @@ -124,7 +115,7 @@ mod tests { ); let (time, ids) = parse_notes(input)?; - let timestamp = find_incrementing(&ids); + let timestamp = find_gauss(&ids); assert_eq!(timestamp, 3417); @@ -140,7 +131,7 @@ mod tests { ); let (time, ids) = parse_notes(input)?; - let timestamp = find_incrementing(&ids); + let timestamp = find_gauss(&ids); assert_eq!(timestamp, 1068781); @@ -156,7 +147,7 @@ mod tests { ); let (time, ids) = parse_notes(input)?; - let timestamp = find_incrementing(&ids); + let timestamp = find_gauss(&ids); assert_eq!(timestamp, 754018); @@ -172,7 +163,7 @@ mod tests { ); let (time, ids) = parse_notes(input)?; - let timestamp = find_incrementing(&ids); + let timestamp = find_gauss(&ids); assert_eq!(timestamp, 779210);