use nom::{ character::complete::{i64, line_ending}, combinator::map, multi::separated_list1, IResult, }; use std::fs; fn main() -> Result<(), Box> { let input = fs::read_to_string("inputs/day_20.txt")?; let coordinates = GroveCoordinates::parser(&input).unwrap().1; { let mut coordinates_1 = coordinates.clone(); coordinates_1.mix(); dbg!(coordinates_1.coordinate_sum()); } { let mut coordinates_2 = coordinates.clone(); coordinates_2.decrypt(811589153); dbg!(coordinates_2.coordinate_sum()); } Ok(()) } #[derive(Debug, Clone)] struct GroveCoordinates(Vec); #[derive(Debug, Clone, Copy)] struct CoordinatePoint { val: i64, original_order: usize, } impl GroveCoordinates { fn parser(input: &str) -> IResult<&str, Self> { map(separated_list1(line_ending, i64), |points| { GroveCoordinates( points .into_iter() .enumerate() .map(|(original_order, val)| CoordinatePoint { val, original_order, }) .collect(), ) })(input) } fn decrypt(&mut self, key: i64) { for p in &mut self.0 { p.val *= key; } for _ in 0..10 { self.mix(); } } fn mix(&mut self) { for original_i in 0..self.0.len() { let encrypted_i = self .0 .iter() .position(|p| p.original_order == original_i) .unwrap(); let to_move = self.0.remove(encrypted_i); let mut destination_i = encrypted_i as i64 + to_move.val; destination_i %= self.0.len() as i64; if destination_i < 0 { destination_i += self.0.len() as i64; } self.0.insert(destination_i as usize, to_move); } } fn get(&self, i: usize) -> i64 { self.0[i % self.0.len()].val } fn coordinate_sum(&self) -> i64 { let zero_position = self.0.iter().position(|p| p.val == 0).unwrap(); self.get(zero_position + 1000) + self.get(zero_position + 2000) + self.get(zero_position + 3000) } }