From b851d2bbe6350555c6faf2313c7e0465e8acf4cd Mon Sep 17 00:00:00 2001 From: Stefan Schwarz Date: Sun, 24 May 2020 13:11:25 +0200 Subject: [PATCH] day12 --- Cargo.toml | 6 +- src/day12/main.rs | 332 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 337 insertions(+), 1 deletion(-) create mode 100644 src/day12/main.rs diff --git a/Cargo.toml b/Cargo.toml index 3ee5431..719d289 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,4 +36,8 @@ path = "src/day9/main.rs" [[bin]] name = "day10" -path = "src/day10/main.rs" \ No newline at end of file +path = "src/day10/main.rs" + +[[bin]] +name = "day12" +path = "src/day12/main.rs" diff --git a/src/day12/main.rs b/src/day12/main.rs new file mode 100644 index 0000000..367448f --- /dev/null +++ b/src/day12/main.rs @@ -0,0 +1,332 @@ +use std::cmp::Ordering; +use std::collections::hash_map::DefaultHasher; +use std::collections::HashMap; +use std::hash::{Hash, Hasher}; +use std::iter::FromIterator; + +#[derive(PartialEq, Debug, Default, Clone, Hash)] +struct Object { + x: isize, + y: isize, + z: isize, +} + +impl From<(isize, isize, isize)> for Object { + fn from(o: (isize, isize, isize)) -> Self { + Object { + x: o.0, + y: o.1, + z: o.2, + } + } +} + +impl Object { + fn attract(&self, other: &Object, v: &mut Object) { + v.x += Object::cmp(self.x, other.x); + v.y += Object::cmp(self.y, other.y); + v.z += Object::cmp(self.z, other.z); + } + + fn apply(&mut self, v: &Object) { + self.x += v.x; + self.y += v.y; + self.z += v.z; + } + + fn cmp(a: isize, b: isize) -> isize { + match b.cmp(&a) { + Ordering::Less => -1, + Ordering::Equal => 0, + Ordering::Greater => 1, + } + } + + fn energy(&self) -> usize { + return (self.x.abs() + self.y.abs() + self.z.abs()) as usize; + } +} + +struct Space { + iteration: u128, + moons: Vec, + velocy: Vec, +} + +impl From> for Space { + fn from(moons: Vec) -> Self { + let iteration = 0; + let velocy = Vec::from_iter((0..moons.len()).map(|_| Object::default())); + Space { + iteration, + moons, + velocy, + } + } +} + +impl Hash for Space { + fn hash(&self, state: &mut H) { + self.moons.iter().for_each(|m| m.hash(state)); + self.velocy.iter().for_each(|v| v.hash(state)); + } +} + +impl Space { + fn step(&mut self) { + self.iteration += 1; + let moons: &mut Vec = self.moons.as_mut(); + let velocy: &mut Vec = self.velocy.as_mut(); + + moons.iter().enumerate().for_each(|(idx, a)| { + moons.iter().for_each(|b| { + if a == b { + return; + } + a.attract(b, velocy.get_mut(idx).unwrap()) + }) + }); + moons + .iter_mut() + .enumerate() + .for_each(|(idx, m)| m.apply(velocy.get(idx).unwrap())); + } + + fn status(&self) -> impl Iterator { + self.moons + .iter() + .zip(self.velocy.iter()) + .map(|(a, b)| (a, b)) + } + + fn iteration(&self) -> u128 { + return self.iteration; + } + + fn hashed(&self) -> u64 { + let mut hash = DefaultHasher::new(); + self.hash(&mut hash); + hash.finish() + } + + fn reapeats(mut self) -> u128 { + let mut known: HashMap = HashMap::new(); + loop { + println!("a lot"); + known.insert(self.hashed(), self.iteration()); + // 4686774924 + for _ in 0..10000000 { + self.step(); + if let Some(iteration) = known.get(&self.hashed()) { + let ago = self.iteration() - iteration; + return ago; + } + } + } + } +} + +#[derive(Eq, PartialEq, Clone)] +struct Axis { + p: isize, +} + +impl From for Axis { + fn from(p: isize) -> Self { + Axis { p } + } +} + +impl Axis { + fn attract(&self, other: &Axis, v: &mut Axis) { + v.p += Axis::cmp(self.p, other.p); + } + + fn apply(&mut self, v: &Axis) { + self.p += v.p; + } + + fn cmp(a: isize, b: isize) -> isize { + match b.cmp(&a) { + Ordering::Less => -1, + Ordering::Equal => 0, + Ordering::Greater => 1, + } + } + + fn energy(&self) -> usize { + return self.p.abs() as usize; + } +} + +struct AxisSpace { + iteration: usize, + moons: Vec, + velocy: Vec, +} + +impl From> for AxisSpace { + fn from(moons: Vec) -> Self { + let iteration = 0; + let moons = Vec::from_iter(moons.iter().map(|i| Axis::from(*i))); + let velocy = Vec::from_iter((0..moons.len()).map(|_| Axis::from(0))); + AxisSpace { + iteration, + moons, + velocy, + } + } +} + +impl AxisSpace { + fn step(&mut self) { + self.iteration += 1; + let moons: &mut Vec = self.moons.as_mut(); + let velocy: &mut Vec = self.velocy.as_mut(); + moons.iter().enumerate().for_each(|(idx, a)| { + moons.iter().for_each(|b| { + if a == b { + return; + } + a.attract(&b, &mut velocy[idx]) + }) + }); + moons + .iter_mut() + .enumerate() + .for_each(|(idx, m)| m.apply(velocy.get(idx).unwrap())); + } + + fn iteration(&self) -> usize { + return self.iteration; + } + + fn reapeats(mut self) -> usize { + let want = self.moons.clone(); + self.step(); + while self.moons != want { + self.step(); + } + return self.iteration() + 1; + } +} + +fn gcd(x: usize, y: usize) -> usize { + let mut x = x; + let mut y = y; + while y != 0 { + let t = y; + y = x % y; + x = t; + } + x +} + +fn lcm(a: usize, b: usize) -> usize { + a * b / gcd(a, b) +} + +fn lcm3(a: usize, b: usize, c: usize) -> usize { + lcm(a, lcm(b, c)) +} + +fn main() { + // part1 + let moons = vec![ + Object::from((17, 5, 1)), + Object::from((-2, -8, 8)), + Object::from((7, -6, 14)), + Object::from((1, -10, 4)), + ]; + let mut space = Space::from(moons); + let mut step_energy = 0; + (1..=100).for_each(|_i| { + (1..=10).for_each(|_| { + space.step(); + }); + step_energy = space + .status() + .map(|(o, v)| o.energy() * v.energy()) + .fold(0, |mut acc, c| { + acc += c; + acc + }); + }); + println!("energy: {}", step_energy); + + // part2 + let xspace = AxisSpace::from(vec![-1, 2, 4, 3]); + let yspace = AxisSpace::from(vec![0, -10, -8, 5]); + let zspace = AxisSpace::from(vec![2, -7, 8, -1]); + let total = lcm3(xspace.reapeats(), yspace.reapeats(), zspace.reapeats()); + println!("matching space found {} iterations ago", total); + + let xspace = AxisSpace::from(vec![-8, 5, 2, 9]); + let yspace = AxisSpace::from(vec![-10, 5, -7, -8]); + let zspace = AxisSpace::from(vec![0, 10, 3, -3]); + let total = lcm3(xspace.reapeats(), yspace.reapeats(), zspace.reapeats()); + println!("matching space found {} iterations ago", total); + + let xspace = AxisSpace::from(vec![17, -2, 7, 1]); + let yspace = AxisSpace::from(vec![5, -8, -6, -10]); + let zspace = AxisSpace::from(vec![1, 8, 14, 4]); + let total = lcm3(xspace.reapeats(), yspace.reapeats(), zspace.reapeats()); + println!("matching space found {} iterations ago", total); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn day12example1() { + let space = Space::from(vec![ + Object::from((-1, 0, 2)), + Object::from((2, -10, -7)), + Object::from((4, -8, 8)), + Object::from((3, 5, -1)), + ]); + assert!(space.status().eq(vec![ + (&Object::from((-1, 0, 2)), &Object::default()), + (&Object::from((2, -10, -7)), &Object::from((0, 0, 0))), + (&Object::from((4, -8, 8)), &Object::from((0, 0, 0))), + (&Object::from((3, 5, -1)), &Object::from((0, 0, 0))), + ])); + } + + #[test] + fn day12part1() { + let mut space = Space::from(vec![ + Object::from((17, 5, 1)), + Object::from((-2, -8, 8)), + Object::from((7, -6, 14)), + Object::from((1, -10, 4)), + ]); + (1..=1000).for_each(|_| { + space.step(); + }); + + let energy = space + .status() + .map(|(o, v)| { + println!("{:?} {:?}", o, v); + o.energy() * v.energy() + }) + .fold(0, |mut acc, c| { + acc += c; + acc + }); + assert_eq!(energy, 9876) + } + + #[test] + fn day12example2() { + let space = Space::from(vec![ + Object::from((-1, 0, 2)), + Object::from((2, -10, -7)), + Object::from((4, -8, 8)), + Object::from((3, 5, -1)), + ]); + assert_eq!(space.reapeats(), 2772) + } +}