mirror of
https://github.com/wezm/advent-of-code.git
synced 2024-12-18 18:29:55 +00:00
Day 12 part 1
This commit is contained in:
parent
ad2ba6a16a
commit
b85d5bcf0a
4 changed files with 213 additions and 0 deletions
35
2019/Cargo.lock
generated
35
2019/Cargo.lock
generated
|
@ -3,4 +3,39 @@
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "advent-of-code"
|
name = "advent-of-code"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
||||||
|
"checksum itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
|
||||||
|
"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd"
|
||||||
|
"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
|
||||||
|
|
|
@ -7,3 +7,5 @@ edition = "2018"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
itertools = "0.8"
|
||||||
|
regex = { version = "1.0", default-features = false, features = ["std", "unicode-perl"] }
|
4
2019/input/day12.txt
Normal file
4
2019/input/day12.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<x=8, y=0, z=8>
|
||||||
|
<x=0, y=-5, z=-10>
|
||||||
|
<x=16, y=10, z=-5>
|
||||||
|
<x=19, y=-10, z=-7>
|
172
2019/src/bin/day12.rs
Normal file
172
2019/src/bin/day12.rs
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
use itertools::Itertools;
|
||||||
|
use regex::Regex;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::{fs, io, ops};
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
struct Point3D {
|
||||||
|
x: i64,
|
||||||
|
y: i64,
|
||||||
|
z: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Moon {
|
||||||
|
position: Point3D,
|
||||||
|
velocity: Point3D,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
let mut moons = parse_positions(&fs::read_to_string("input/day12.txt")?)?;
|
||||||
|
|
||||||
|
for _i in 0..1000 {
|
||||||
|
step(&mut moons);
|
||||||
|
}
|
||||||
|
let system: Vec<_> = moons.into_iter().map(|moon| moon.unwrap()).collect();
|
||||||
|
println!("Part 1: {}", total_energy(&system));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_positions(s: &str) -> io::Result<Vec<Option<Moon>>> {
|
||||||
|
let positions: Vec<Point3D> = s
|
||||||
|
.lines()
|
||||||
|
.map(|line| line.parse())
|
||||||
|
.collect::<Result<_, _>>()
|
||||||
|
.map_err(|_| io::Error::new(io::ErrorKind::Other, "parse error"))?;
|
||||||
|
|
||||||
|
Ok(positions
|
||||||
|
.into_iter()
|
||||||
|
.map(|position| {
|
||||||
|
Some(Moon {
|
||||||
|
position,
|
||||||
|
velocity: Point3D { x: 0, y: 0, z: 0 },
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn step(system: &mut Vec<Option<Moon>>) {
|
||||||
|
// Within each time step, first update the velocity of every moon by applying gravity.
|
||||||
|
// Then, once all moons' velocities have been updated, update the position of every moon
|
||||||
|
// by applying velocity.
|
||||||
|
|
||||||
|
// To apply gravity, consider every pair of moons. On each axis (x, y, and z), the velocity of
|
||||||
|
// each moon changes by exactly +1 or -1 to pull the moons together. For example, if Ganymede
|
||||||
|
// has an x position of 3, and Callisto has a x position of 5, then Ganymede's x velocity
|
||||||
|
// changes by +1 (because 5 > 3) and Callisto's x velocity changes by -1 (because 3 < 5).
|
||||||
|
// However, if the positions on a given axis are the same, the velocity on that axis does not
|
||||||
|
// change for that pair of moons.
|
||||||
|
|
||||||
|
// Hackery....
|
||||||
|
for pair in (0..system.len()).combinations(2) {
|
||||||
|
let mut moon1 = system[pair[0]].take().unwrap();
|
||||||
|
let mut moon2 = system[pair[1]].take().unwrap();
|
||||||
|
moon1.apply_gravity(&mut moon2);
|
||||||
|
system[pair[0]].replace(moon1);
|
||||||
|
system[pair[1]].replace(moon2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once all gravity has been applied, apply velocity: simply add the velocity of each moon to
|
||||||
|
// its own position.
|
||||||
|
for opt_moon in system {
|
||||||
|
if let Some(moon) = opt_moon {
|
||||||
|
moon.apply_velocity()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn total_energy(system: &[Moon]) -> i64 {
|
||||||
|
system.iter().map(|moon| moon.total_energy()).sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Moon {
|
||||||
|
fn apply_gravity(&mut self, other: &mut Moon) {
|
||||||
|
if self.position.x == other.position.x {
|
||||||
|
} else if self.position.x < other.position.x {
|
||||||
|
self.velocity.x += 1;
|
||||||
|
other.velocity.x -= 1;
|
||||||
|
} else {
|
||||||
|
self.velocity.x -= 1;
|
||||||
|
other.velocity.x += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.position.y == other.position.y {
|
||||||
|
} else if self.position.y < other.position.y {
|
||||||
|
self.velocity.y += 1;
|
||||||
|
other.velocity.y -= 1;
|
||||||
|
} else {
|
||||||
|
self.velocity.y -= 1;
|
||||||
|
other.velocity.y += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.position.z == other.position.z {
|
||||||
|
} else if self.position.z < other.position.z {
|
||||||
|
self.velocity.z += 1;
|
||||||
|
other.velocity.z -= 1;
|
||||||
|
} else {
|
||||||
|
self.velocity.z -= 1;
|
||||||
|
other.velocity.z += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_velocity(&mut self) {
|
||||||
|
self.position += self.velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The total energy for a single moon is its potential energy multiplied by its kinetic energy.
|
||||||
|
// A moon's potential energy is the sum of the absolute values of its x, y, and z position
|
||||||
|
// coordinates. A moon's kinetic energy is the sum of the absolute values of its velocity
|
||||||
|
// coordinates.
|
||||||
|
fn potential_energy(&self) -> i64 {
|
||||||
|
self.position.x.abs() + self.position.y.abs() + self.position.z.abs()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kinetic_energy(&self) -> i64 {
|
||||||
|
self.velocity.x.abs() + self.velocity.y.abs() + self.velocity.z.abs()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn total_energy(&self) -> i64 {
|
||||||
|
self.potential_energy() * self.kinetic_energy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Point3D {
|
||||||
|
type Err = std::num::ParseIntError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let re = Regex::new(r"^<x=([\d-]+), y=([\d-]+), z=([\d-]+)>$").unwrap();
|
||||||
|
let caps = re.captures(s.trim()).unwrap();
|
||||||
|
|
||||||
|
Ok(Point3D {
|
||||||
|
x: caps[1].parse()?,
|
||||||
|
y: caps[2].parse()?,
|
||||||
|
z: caps[3].parse()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::AddAssign for Point3D {
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
self.x += rhs.x;
|
||||||
|
self.y += rhs.y;
|
||||||
|
self.z += rhs.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_example() {
|
||||||
|
let input = "<x=-1, y=0, z=2>
|
||||||
|
<x=2, y=-10, z=-7>
|
||||||
|
<x=4, y=-8, z=8>
|
||||||
|
<x=3, y=5, z=-1>
|
||||||
|
";
|
||||||
|
let mut moons = parse_positions(input).unwrap();
|
||||||
|
step(&mut moons);
|
||||||
|
dbg!(moons);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue