day12
This commit is contained in:
parent
9b09b974eb
commit
b851d2bbe6
2 changed files with 337 additions and 1 deletions
|
@ -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
332
src/day12/main.rs
Normal 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)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue