Rewrote part 2 using Chinese Remainder theorem
This commit is contained in:
		
							parent
							
								
									f87e5ea0af
								
							
						
					
					
						commit
						fdbbd934a4
					
				
							
								
								
									
										7
									
								
								aoc_2024/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										7
									
								
								aoc_2024/Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -55,6 +55,7 @@ dependencies = [
 | 
				
			|||||||
 "hashbrown",
 | 
					 "hashbrown",
 | 
				
			||||||
 "nom",
 | 
					 "nom",
 | 
				
			||||||
 "num",
 | 
					 "num",
 | 
				
			||||||
 | 
					 "num-modular",
 | 
				
			||||||
 "regex",
 | 
					 "regex",
 | 
				
			||||||
 "topological-sort",
 | 
					 "topological-sort",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
@ -169,6 +170,12 @@ dependencies = [
 | 
				
			|||||||
 "num-traits",
 | 
					 "num-traits",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "num-modular"
 | 
				
			||||||
 | 
					version = "0.6.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "num-rational"
 | 
					name = "num-rational"
 | 
				
			||||||
version = "0.4.2"
 | 
					version = "0.4.2"
 | 
				
			||||||
 | 
				
			|||||||
@ -9,5 +9,6 @@ aoc-runner-derive = "0.3.0"
 | 
				
			|||||||
hashbrown = "0.15.2"
 | 
					hashbrown = "0.15.2"
 | 
				
			||||||
nom = "7.1.3"
 | 
					nom = "7.1.3"
 | 
				
			||||||
num = "0.4.3"
 | 
					num = "0.4.3"
 | 
				
			||||||
 | 
					num-modular = "0.6.1"
 | 
				
			||||||
regex = "1.11.1"
 | 
					regex = "1.11.1"
 | 
				
			||||||
topological-sort = "0.2.2"
 | 
					topological-sort = "0.2.2"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,3 @@
 | 
				
			|||||||
use std::sync::OnceLock;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use aoc_runner_derive::{aoc, aoc_generator};
 | 
					use aoc_runner_derive::{aoc, aoc_generator};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use nom::{
 | 
					use nom::{
 | 
				
			||||||
@ -10,6 +8,8 @@ use nom::{
 | 
				
			|||||||
    sequence::{preceded, separated_pair},
 | 
					    sequence::{preceded, separated_pair},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use num_modular::ModularPow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Input = Vec<((i64, i64), (i64, i64))>;
 | 
					type Input = Vec<((i64, i64), (i64, i64))>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[aoc_generator(day14)]
 | 
					#[aoc_generator(day14)]
 | 
				
			||||||
@ -54,43 +54,42 @@ fn part1(input: &Input) -> i64 {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[aoc(day14, part2)]
 | 
					#[aoc(day14, part2)]
 | 
				
			||||||
fn part2(input: &Input) -> usize {
 | 
					fn part2(input: &Input) -> i64 {
 | 
				
			||||||
    let (w, h) = (101, 103);
 | 
					    let (w, h) = (101, 103);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut input = input.clone();
 | 
					    let mut offset_x = 0;
 | 
				
			||||||
 | 
					    let mut min_var = f64::INFINITY;
 | 
				
			||||||
    let mut iter = 0;
 | 
					    for t in 0..w {
 | 
				
			||||||
 | 
					        let values = input.iter().map(|((p, _), (v, _))| (p + t * (v + w)) % w);
 | 
				
			||||||
    loop {
 | 
					        let mean = values.clone().sum::<i64>() as f64 / input.len() as f64;
 | 
				
			||||||
        iter += 1;
 | 
					        let variance = values
 | 
				
			||||||
 | 
					            .map(|v| (v as f64 - mean) * (v as f64 - mean))
 | 
				
			||||||
        let mut total = (0f64, 0f64);
 | 
					 | 
				
			||||||
        input = input
 | 
					 | 
				
			||||||
            .into_iter()
 | 
					 | 
				
			||||||
            .map(|((px, py), (vx, vy))| {
 | 
					 | 
				
			||||||
                let (px, py) = ((px + vx + w) % w, (py + vy + h) % h);
 | 
					 | 
				
			||||||
                total.0 += px as f64;
 | 
					 | 
				
			||||||
                total.1 += py as f64;
 | 
					 | 
				
			||||||
                ((px, py), (vx, vy))
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            .collect();
 | 
					 | 
				
			||||||
        let mean = (total.0 / input.len() as f64, total.1 / input.len() as f64);
 | 
					 | 
				
			||||||
        let variance = input
 | 
					 | 
				
			||||||
            .iter()
 | 
					 | 
				
			||||||
            .map(|((px, py), _)| {
 | 
					 | 
				
			||||||
                let dx = *px as f64 - mean.0;
 | 
					 | 
				
			||||||
                let dy = *py as f64 - mean.1;
 | 
					 | 
				
			||||||
                dx * dx + dy * dy
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            .sum::<f64>()
 | 
					            .sum::<f64>()
 | 
				
			||||||
            / input.len() as f64;
 | 
					            / input.len() as f64;
 | 
				
			||||||
 | 
					        if variance < min_var {
 | 
				
			||||||
        if variance < 1000.0 {
 | 
					            min_var = variance;
 | 
				
			||||||
            break;
 | 
					            offset_x = t;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    iter
 | 
					    let mut offset_y = 0;
 | 
				
			||||||
 | 
					    let mut min_var = f64::INFINITY;
 | 
				
			||||||
 | 
					    for t in 0..h {
 | 
				
			||||||
 | 
					        let values = input.iter().map(|((_, p), (_, v))| (p + t * (v + h)) % h);
 | 
				
			||||||
 | 
					        let mean = values.clone().sum::<i64>() as f64 / input.len() as f64;
 | 
				
			||||||
 | 
					        let variance = values
 | 
				
			||||||
 | 
					            .map(|v| (v as f64 - mean) * (v as f64 - mean))
 | 
				
			||||||
 | 
					            .sum::<f64>()
 | 
				
			||||||
 | 
					            / input.len() as f64;
 | 
				
			||||||
 | 
					        if variance < min_var {
 | 
				
			||||||
 | 
					            min_var = variance;
 | 
				
			||||||
 | 
					            offset_y = t;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let invmod_x = (w as u64).powm((h - 2) as u64, &(h as u64)) as i64;
 | 
				
			||||||
 | 
					    let invmod_y = (h as u64).powm((w - 2) as u64, &(w as u64)) as i64;
 | 
				
			||||||
 | 
					    (offset_x * h * invmod_x + offset_y * w * invmod_y) % (w * h)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user