diff --git a/src/bin/d20p1.rs b/src/bin/d20p1.rs new file mode 100644 index 0000000..176a58b --- /dev/null +++ b/src/bin/d20p1.rs @@ -0,0 +1,9 @@ +use aoc22::{day20, util}; + +pub fn main() { + let nodes = day20::parse_file(&util::parse_input()); + + day20::mix(&nodes); + + println!("Sum of coordinates: {}", day20::calc_coordinates(&nodes)); +} diff --git a/src/day20.rs b/src/day20.rs new file mode 100644 index 0000000..39c6558 --- /dev/null +++ b/src/day20.rs @@ -0,0 +1,118 @@ +use std::{cell::RefCell, fmt::Debug, ops::Deref, rc::Rc}; + +pub struct Node { + pub val: isize, + pub next: Option>>, + pub prev: Option>>, +} + +// Default Debug implementation will loop indefinitely, since we have a ring buffer +impl Debug for Node { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Node") + .field("val", &self.val) + .field("next", &self.next.as_ref().map(|n| n.borrow().val)) + .field("prev", &self.prev.as_ref().map(|n| n.borrow().val)) + .finish() + } +} + +pub fn get_next(node: &Rc>, n: usize) -> Rc> { + let mut curr = node.clone(); + for _ in 0..n { + let next = curr.borrow().next.as_ref().unwrap().clone(); + curr = next; + } + curr +} + +pub fn get_prev(node: &Rc>, n: usize) -> Rc> { + let mut curr = node.clone(); + for _ in 0..n { + let prev = curr.borrow().prev.as_ref().unwrap().clone(); + curr = prev; + } + curr +} + +pub fn parse_file(input: &String) -> Vec>> { + let mut result = Vec::new(); + + let mut last = None; + for line in input.lines() { + let val: isize = line.parse().unwrap(); + let node = Rc::new(RefCell::new(Node { + val, + next: None, + prev: last.clone(), + })); + if let Some(l) = last { + l.as_ref().borrow_mut().next = Some(node.clone()); + } + result.push(node.clone()); + last = Some(node); + } + + assert!(result.len() > 0); + + let last_refcell = last.as_ref().unwrap().deref(); + last_refcell.borrow_mut().next = Some(result[0].clone()); + let first_refcell = &*result[0]; + first_refcell.borrow_mut().prev = Some(last.as_ref().unwrap().clone()); + + result +} + +pub fn mix(nodes: &Vec>>) { + for node in nodes { + let n = node.borrow().val; + if n == 0 { + continue; + } + + // Remove from current position + let prev = get_prev(node, 1); + let next = get_next(node, 1); + prev.borrow_mut().next = Some(next.clone()); + next.borrow_mut().prev = Some(prev.clone()); + + let prev = if n > 0 { + get_next(node, n as usize) + } else { + get_prev(node, (-n as usize) + 1) + }; + let next = get_next(&prev, 1); + prev.deref().borrow_mut().next = Some(node.clone()); + next.deref().borrow_mut().prev = Some(node.clone()); + + let mut n_mut = node.deref().borrow_mut(); + n_mut.prev = Some(prev.clone()); + n_mut.next = Some(next.clone()); + drop(n_mut); + + // print_nodes(&nodes); + } +} + +pub fn print_nodes(nodes: &Vec>>) { + let mut curr = nodes.iter().find(|n| n.borrow().val == 0).unwrap().clone(); + loop { + print!("{}, ", curr.borrow().val); + + let next = curr.borrow().next.as_ref().unwrap().clone(); + curr = next; + if curr.borrow().val == 0 { + break; + } + } + print!("\n"); +} + +pub fn calc_coordinates(nodes: &Vec>>) -> isize { + let zero = nodes.iter().find(|n| n.borrow().val == 0).unwrap(); + let first = get_next(zero, 1000).borrow().val; + let second = get_next(zero, 2000).borrow().val; + let third = get_next(zero, 3000).borrow().val; + + first + second + third +} diff --git a/src/lib.rs b/src/lib.rs index c978299..e63c09b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ pub mod day17; pub mod day18; pub mod day19; pub mod day2; +pub mod day20; pub mod day3; pub mod day4; pub mod day5;