This commit is contained in:
Max Känner 2022-12-09 15:15:50 +01:00
parent 7fc068d87b
commit d61cb31103
3 changed files with 2176 additions and 2 deletions

7
day9/Cargo.lock generated Normal file
View 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

File diff suppressed because it is too large Load Diff

View File

@ -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()
);
}