mirror of
https://github.com/wezm/advent-of-code.git
synced 2024-12-18 10:19: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]]
|
||||
name = "advent-of-code"
|
||||
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
|
||||
|
||||
[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