summaryrefslogtreecommitdiff
path: root/advent/src/12.rs
blob: 3396d62d58b678423737ee0ce320bc64923d0fd3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// [nix-shell:~/projects/sandbox/advent]$ cargo run --bin 12
//     Compiling advent v0.1.0 (/home/orbekk/projects/sandbox/advent)
//     Finished dev [unoptimized + debuginfo] target(s) in 0.40s
//     Running `target/debug/12`
// After 10 steps:
// pos=<x=  2, y=  1, z= -3>, vel=<x= -3, y= -2, z=  1>
// pos=<x=  1, y= -8, z=  0>, vel=<x= -1, y=  1, z=  3>
// pos=<x=  3, y= -6, z=  1>, vel=<x=  3, y=  2, z= -3>
// pos=<x=  2, y=  0, z=  4>, vel=<x=  1, y= -1, z= -1>
//
// energy=179
//
// After 1000 steps:
// pos=<x=-26, y= 45, z=-31>, vel=<x=  2, y= 17, z=  6>
// pos=<x= 87, y= 23, z=-12>, vel=<x=-14, y=-13, z=  9>
// pos=<x=-33, y= -2, z=-24>, vel=<x= -2, y=-15, z= -5>
// pos=<x=-20, y=-86, z= 77>, vel=<x= 14, y= 11, z=-10>
//
// energy=14645
use std::fmt;

#[derive(Debug)]
struct Moon {
    position: (i64, i64, i64),
    velocity: (i64, i64, i64),
}

fn sign(x: i64) -> i64 {
    if x < 0 {
        -1
    } else if x > 0 {
        1
    } else {
        0
    }
}

impl Moon {
    fn step(&self, moons: &Vec<Moon>) -> Moon {
        let (x, y, z) = self.position;
        let (mut gx, mut gy, mut gz) = self.velocity;
        for moon in moons {
            let (ox, oy, oz) = moon.position;
            gx += sign(ox - x);
            gy += sign(oy - y);
            gz += sign(oz - z);
        }
        let position = (x + gx, y + gy, z + gz);
        Moon { position: position, velocity: (gx, gy, gz) }
    }

    fn energy(&self) -> i64 {
        let (x, y, z) = self.position;
        let (p, q, r) = self.velocity;
        (x.abs() + y.abs() + z.abs()) * (p.abs() + q.abs() + r.abs())
    }
}

fn make_moon(x: i64, y: i64, z: i64) -> Moon {
    Moon { position: (x, y, z), velocity: (0, 0, 0) }
}

impl fmt::Display for Moon {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let (x, y, z) = self.position;
        let (p, q, r) = self.velocity;
        write!(f, "pos=<x={:3}, y={:3}, z={:3}>, vel=<x={:3}, y={:3}, z={:3}>",
                x, y, z, p, q, r)
    }
}

#[derive(Debug)]
struct Moons(Vec<Moon>);

impl Moons {
    fn step(&self) -> Moons {
        Moons(self.0.iter().map(|m| m.step(&self.0)).collect())
    }

    fn energy(&self) -> i64 {
        self.0.iter().map(|m| m.energy()).sum()
    }
}

impl fmt::Display for Moons {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        for moon in &self.0 {
            moon.fmt(f)?;
            write!(f, "\n")?;
        }
        Ok(())
    }
}

fn run_steps(mut m: Moons, steps: i64, debug: bool) {
    for i in 0..steps {
        if debug {
            println!("After {} steps:", i);
            println!("{}", m);
        }
        m = m.step()
    }
    println!("After {} steps:", steps);
    println!("{}", m);
    println!("energy={:3}", m.energy())
}

fn main() {
    let _ex1 = Moons(vec!(
        make_moon(-1, 0, 2),
        make_moon(2, -10, -7),
        make_moon(4, -8, 8),
        make_moon(3, 5, -1),
    ));
    let _ex2 = Moons(vec!(
        make_moon(-8, -10, 0),
        make_moon(5, 5, 10),
        make_moon(2, -7, 3),
        make_moon(9, -8, -3),
        ));
    run_steps(_ex1, 10, false);
    println!();
    run_steps(_ex2, 1000, false);
}