Day 9
This commit is contained in:
parent
7fc068d87b
commit
d61cb31103
7
day9/Cargo.lock
generated
Normal file
7
day9/Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day9"
|
||||||
|
version = "0.1.0"
|
2000
day9/input.txt
Normal file
2000
day9/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
171
day9/src/main.rs
171
day9/src/main.rs
@ -1,3 +1,170 @@
|
|||||||
fn main() {
|
use std::{
|
||||||
println!("Hello, world!");
|
collections::HashSet,
|
||||||
|
fs::read_to_string,
|
||||||
|
mem::MaybeUninit,
|
||||||
|
ops::{Add, AddAssign, Sub, SubAssign},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
|
||||||
|
enum Direction {
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&str> for Direction {
|
||||||
|
type Error = &'static str;
|
||||||
|
|
||||||
|
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
"U" => Ok(Self::Up),
|
||||||
|
"D" => Ok(Self::Down),
|
||||||
|
"L" => Ok(Self::Left),
|
||||||
|
"R" => Ok(Self::Right),
|
||||||
|
_ => Err("invalid Direction"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
|
||||||
|
struct Movement {
|
||||||
|
direction: Direction,
|
||||||
|
steps: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&str> for Movement {
|
||||||
|
type Error = &'static str;
|
||||||
|
|
||||||
|
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||||
|
let words = value.split_whitespace().collect::<Vec<_>>();
|
||||||
|
match &words[..] {
|
||||||
|
[direction, steps] => Ok(Movement {
|
||||||
|
direction: Direction::try_from(*direction)?,
|
||||||
|
steps: match steps.parse::<usize>() {
|
||||||
|
Ok(it) => it,
|
||||||
|
Err(_) => return Err("unable to parse steps"),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
_ => Err("Need 2 words in format [Direction] [Steps]"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone, Copy, Default, Hash)]
|
||||||
|
struct Position {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for Position {
|
||||||
|
type Output = Position;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x + rhs.x,
|
||||||
|
y: self.y + rhs.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign for Position {
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
self.x += rhs.x;
|
||||||
|
self.y += rhs.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for Position {
|
||||||
|
type Output = Position;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x - rhs.x,
|
||||||
|
y: self.y - rhs.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign for Position {
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
self.x += rhs.x;
|
||||||
|
self.y += rhs.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone, Default)]
|
||||||
|
struct Link {
|
||||||
|
head: Position,
|
||||||
|
tail: Position,
|
||||||
|
tail_positions: HashSet<Position>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Link {
|
||||||
|
fn simulate_position(&mut self, head_position: &Position) {
|
||||||
|
self.head = *head_position;
|
||||||
|
let distance = self.head - self.tail;
|
||||||
|
if distance.x.abs() > 1 || distance.y.abs() > 1 {
|
||||||
|
self.tail.x += distance.x.signum();
|
||||||
|
self.tail.y += distance.y.signum();
|
||||||
|
}
|
||||||
|
self.tail_positions.insert(self.tail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
struct Rope<const N: usize> {
|
||||||
|
links: [Link; N],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> Rope<N> {
|
||||||
|
fn simulate(mut self, movement: &Movement) -> Self {
|
||||||
|
for _ in 0..movement.steps {
|
||||||
|
let head_position = self.links[0].head
|
||||||
|
+ match movement.direction {
|
||||||
|
Direction::Up => Position { x: 0, y: -1 },
|
||||||
|
Direction::Down => Position { x: 0, y: 1 },
|
||||||
|
Direction::Left => Position { x: -1, y: 0 },
|
||||||
|
Direction::Right => Position { x: 1, y: 0 },
|
||||||
|
};
|
||||||
|
self.links[0].simulate_position(&head_position);
|
||||||
|
for i in 1..self.links.len() {
|
||||||
|
let previous = self.links[i - 1].tail;
|
||||||
|
self.links[i].simulate_position(&previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> Default for Rope<N> {
|
||||||
|
fn default() -> Self {
|
||||||
|
let mut links: [Link; N] = unsafe { MaybeUninit::zeroed().assume_init() };
|
||||||
|
links.fill(Default::default());
|
||||||
|
Self { links }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let input = "R 5
|
||||||
|
U 8
|
||||||
|
L 8
|
||||||
|
D 3
|
||||||
|
R 17
|
||||||
|
D 10
|
||||||
|
L 25
|
||||||
|
U 20";
|
||||||
|
let input = read_to_string("input.txt").unwrap_or_else(|_| input.to_owned());
|
||||||
|
|
||||||
|
let rope = input
|
||||||
|
.lines()
|
||||||
|
.flat_map(Movement::try_from)
|
||||||
|
.fold(Rope::<9>::default(), |rope, movement| {
|
||||||
|
rope.simulate(&movement)
|
||||||
|
});
|
||||||
|
println!(
|
||||||
|
"The second knot visited {} positions, the tail visited {} positions",
|
||||||
|
rope.links[0].tail_positions.len(),
|
||||||
|
rope.links[8].tail_positions.len()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user