1
0
Fork 0

Solve day 9

This commit is contained in:
Lars Martens 2022-12-09 12:45:36 +01:00
parent 56fb4342d0
commit ce99b571c0
3 changed files with 2182 additions and 0 deletions

2000
input/09 Normal file

File diff suppressed because it is too large Load diff

8
input/09-test Normal file
View 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
View 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)
})
}