Solve day 9
This commit is contained in:
parent
56fb4342d0
commit
ce99b571c0
3 changed files with 2182 additions and 0 deletions
8
input/09-test
Normal file
8
input/09-test
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
R 4
|
||||||
|
U 4
|
||||||
|
L 3
|
||||||
|
D 1
|
||||||
|
R 4
|
||||||
|
D 1
|
||||||
|
L 5
|
||||||
|
R 2
|
174
src/bin/09.rs
Normal file
174
src/bin/09.rs
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
use std::{
|
||||||
|
collections::HashSet,
|
||||||
|
fmt::Display,
|
||||||
|
iter,
|
||||||
|
ops::{Add, Sub},
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
|
||||||
|
use aoc2022::*;
|
||||||
|
|
||||||
|
const INPUT: &str = include_str!("../../input/09");
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut rope = Rope::new(2);
|
||||||
|
input().for_each(|a| rope.apply(a));
|
||||||
|
solved_level_1(rope.visited.len());
|
||||||
|
|
||||||
|
let mut rope = Rope::new(10);
|
||||||
|
input().for_each(|a| rope.apply(a));
|
||||||
|
solved_level_2(rope.visited.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Rope {
|
||||||
|
nodes: Vec<Position>,
|
||||||
|
visited: HashSet<Position>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rope {
|
||||||
|
fn new(nodes: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
nodes: iter::repeat(Position::default()).take(nodes).collect(),
|
||||||
|
visited: HashSet::from([Position::default()]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&mut self, action: Action) {
|
||||||
|
self.nodes[0] = self.nodes[0] + action.direction();
|
||||||
|
|
||||||
|
for i in 1..self.nodes.len() {
|
||||||
|
let (head, tail) = self.nodes.split_at_mut(i);
|
||||||
|
let head = head.last_mut().unwrap();
|
||||||
|
let tail = tail.first_mut().unwrap();
|
||||||
|
let diff = *head - *tail;
|
||||||
|
|
||||||
|
let pull = if (diff.0 == 0) ^ (diff.1 == 0) {
|
||||||
|
// Horizontal/vertical
|
||||||
|
let pull_x = if diff.0.abs() > 1 { diff.0.signum() } else { 0 };
|
||||||
|
let pull_y = if diff.1.abs() > 1 { diff.1.signum() } else { 0 };
|
||||||
|
Position(pull_x, pull_y)
|
||||||
|
} else if diff.0.abs() > 1 || diff.1.abs() > 1 {
|
||||||
|
// Diagonal
|
||||||
|
Position(diff.0.signum(), diff.1.signum())
|
||||||
|
} else {
|
||||||
|
Position::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
*tail = *tail + pull;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.visited.insert(*self.nodes.last().unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Rope {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
// Find bounds
|
||||||
|
let (min, max) = self.nodes.iter().chain(self.visited.iter()).fold(
|
||||||
|
(Position::default(), Position::default()),
|
||||||
|
|(min, max), p| {
|
||||||
|
(
|
||||||
|
Position(min.0.min(p.0), min.1.min(p.1)),
|
||||||
|
Position(max.0.max(p.0), max.1.max(p.1)),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Print field
|
||||||
|
for y in min.1..=max.1 {
|
||||||
|
for x in min.0..=max.0 {
|
||||||
|
let pos = Position(x, y);
|
||||||
|
|
||||||
|
let mut c = '.';
|
||||||
|
if self.visited.contains(&pos) {
|
||||||
|
c = '#';
|
||||||
|
}
|
||||||
|
if pos.is_zero() {
|
||||||
|
c = 's';
|
||||||
|
}
|
||||||
|
if let Some(node_idx) = self.nodes.iter().position(|&p| p == pos) {
|
||||||
|
c = "H123456789".chars().nth(node_idx).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, "{c}")?;
|
||||||
|
}
|
||||||
|
writeln!(f)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Default, Hash, PartialEq, Eq)]
|
||||||
|
struct Position(i64, i64);
|
||||||
|
|
||||||
|
impl Position {
|
||||||
|
fn is_zero(self) -> bool {
|
||||||
|
self.0 == 0 && self.1 == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for Position {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Self(self.0 + rhs.0, self.1 + rhs.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for Position {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Self(self.0 - rhs.0, self.1 - rhs.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(i64, i64)> for Position {
|
||||||
|
fn from((x, y): (i64, i64)) -> Self {
|
||||||
|
Self(x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum Action {
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Action {
|
||||||
|
type Err = ();
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"R" => Ok(Self::Right),
|
||||||
|
"L" => Ok(Self::Left),
|
||||||
|
"U" => Ok(Self::Up),
|
||||||
|
"D" => Ok(Self::Down),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Action {
|
||||||
|
fn direction(self) -> Position {
|
||||||
|
match self {
|
||||||
|
Action::Up => (0, -1).into(),
|
||||||
|
Action::Down => (0, 1).into(),
|
||||||
|
Action::Left => (-1, 0).into(),
|
||||||
|
Action::Right => (1, 0).into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input() -> impl Iterator<Item = Action> {
|
||||||
|
INPUT.lines().flat_map(|line| {
|
||||||
|
let (action, count) = line.split_once(' ').unwrap();
|
||||||
|
let action: Action = action.parse().unwrap();
|
||||||
|
let count: usize = count.parse().unwrap();
|
||||||
|
iter::repeat(action).take(count)
|
||||||
|
})
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue