This commit is contained in:
Stefan Schwarz 2020-05-24 13:11:25 +02:00
parent 9b09b974eb
commit b851d2bbe6
2 changed files with 337 additions and 1 deletions

View file

@ -36,4 +36,8 @@ path = "src/day9/main.rs"
[[bin]]
name = "day10"
path = "src/day10/main.rs"
path = "src/day10/main.rs"
[[bin]]
name = "day12"
path = "src/day12/main.rs"

332
src/day12/main.rs Normal file
View file

@ -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<Object>,
velocy: Vec<Object>,
}
impl From<Vec<Object>> for Space {
fn from(moons: Vec<Object>) -> 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<H: Hasher>(&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<Object> = self.moons.as_mut();
let velocy: &mut Vec<Object> = 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<Item = (&'_ Object, &'_ Object)> {
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<u64, u128> = 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<isize> 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<Axis>,
velocy: Vec<Axis>,
}
impl From<Vec<isize>> for AxisSpace {
fn from(moons: Vec<isize>) -> 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<Axis> = self.moons.as_mut();
let velocy: &mut Vec<Axis> = 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)
}
}