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() {
|
||||
println!("Hello, world!");
|
||||
use std::{
|
||||
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