day(09): add initial solution
Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
parent
3219400a73
commit
d7d3a8f889
2 changed files with 220 additions and 0 deletions
8
samples/day09.txt
Normal file
8
samples/day09.txt
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
R 4
|
||||||
|
U 4
|
||||||
|
L 3
|
||||||
|
D 1
|
||||||
|
R 4
|
||||||
|
D 1
|
||||||
|
L 5
|
||||||
|
R 2
|
212
src/bin/day09.rs
Normal file
212
src/bin/day09.rs
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
use std::{collections::BTreeSet, str::FromStr};
|
||||||
|
|
||||||
|
use aoc_2022::*;
|
||||||
|
|
||||||
|
use color_eyre::{eyre::eyre, Report};
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
type Input = Vec<Instruction>;
|
||||||
|
type Output = usize;
|
||||||
|
|
||||||
|
enum Direction {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Down,
|
||||||
|
Up,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Direction {
|
||||||
|
fn apply(&self, pos: Position) -> Position {
|
||||||
|
pos + match self {
|
||||||
|
Direction::Left => Position::new(-1, 0),
|
||||||
|
Direction::Right => Position::new(1, 0),
|
||||||
|
Direction::Down => Position::new(0, -1),
|
||||||
|
Direction::Up => Position::new(0, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Direction {
|
||||||
|
type Err = Report;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"L" => Ok(Direction::Left),
|
||||||
|
"R" => Ok(Direction::Right),
|
||||||
|
"D" => Ok(Direction::Down),
|
||||||
|
"U" => Ok(Direction::Up),
|
||||||
|
_ => Err(eyre!("Invalid direction {}", s)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Instruction {
|
||||||
|
direction: Direction,
|
||||||
|
steps: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Instruction {
|
||||||
|
type Err = Report;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let parts = s.split(' ').collect_vec();
|
||||||
|
let (direction, steps) = (parts[0].parse::<Direction>()?, parts[1].parse::<i32>()?);
|
||||||
|
|
||||||
|
Ok(Self { direction, steps })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Position = Vector2D<i32>;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct State {
|
||||||
|
knots: Vec<Position>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
fn new(knots: i32) -> State {
|
||||||
|
Self {
|
||||||
|
knots: (0..knots).map(|_| Position::new(0, 0)).collect_vec(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_step(&self, visited: &mut BTreeSet<Position>, direction: &Direction) -> State {
|
||||||
|
let mut knots = self.knots.clone();
|
||||||
|
|
||||||
|
// move head
|
||||||
|
knots[0] = direction.apply(knots[0]);
|
||||||
|
|
||||||
|
// index of tail
|
||||||
|
let tail = knots.len() - 1;
|
||||||
|
|
||||||
|
// add old position of the tail to the set
|
||||||
|
visited.insert(knots[tail]);
|
||||||
|
|
||||||
|
// move parts towards head
|
||||||
|
for i in 1..knots.len() {
|
||||||
|
let v = knots[i - 1] - knots[i];
|
||||||
|
if v.x().abs() > 1 || v.y().abs() > 1 {
|
||||||
|
let d = Position::new(v.x().signum(), v.y().signum());
|
||||||
|
knots[i] = knots[i] + d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// debug!("\n{}", State { head, tail }.show(6, 5));
|
||||||
|
|
||||||
|
// add new position of the tail to the set
|
||||||
|
visited.insert(knots[tail]);
|
||||||
|
|
||||||
|
State { knots }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute(&self, i: &Instruction) -> (BTreeSet<Position>, State) {
|
||||||
|
let mut visited = BTreeSet::new();
|
||||||
|
|
||||||
|
// debug!("\n{}", self.show(6, 5));
|
||||||
|
let mut state: State = self.clone();
|
||||||
|
for _ in 0..i.steps {
|
||||||
|
state = state.execute_step(&mut visited, &i.direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
(visited, state)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fn show(&self, width: i32, height: i32) -> String {
|
||||||
|
// (0..height)
|
||||||
|
// .rev()
|
||||||
|
// .map(|y| {
|
||||||
|
// (0..width)
|
||||||
|
// .map(|x| {
|
||||||
|
// let pos = Position::new(x, y);
|
||||||
|
|
||||||
|
// if pos == self.head {
|
||||||
|
// 'H'
|
||||||
|
// } else if pos == self.tail {
|
||||||
|
// 'T'
|
||||||
|
// } else {
|
||||||
|
// '.'
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// .join("")
|
||||||
|
// })
|
||||||
|
// .join("\n")
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute(knots: i32, input: &Input) -> Output {
|
||||||
|
let mut visited = BTreeSet::<Position>::new();
|
||||||
|
|
||||||
|
input.iter().fold(State::new(knots), |state, instruction| {
|
||||||
|
let (mut v, s) = state.execute(instruction);
|
||||||
|
visited.append(&mut v);
|
||||||
|
|
||||||
|
s
|
||||||
|
});
|
||||||
|
|
||||||
|
visited.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Day09;
|
||||||
|
impl Solution<Input, Output> for Day09 {
|
||||||
|
fn parse_input<P: AsRef<Path>>(pathname: P) -> Input {
|
||||||
|
file_to_structs(pathname)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_1(input: &Input) -> Output {
|
||||||
|
execute(2, input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_2(input: &Input) -> Output {
|
||||||
|
execute(10, input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
Day09::main()
|
||||||
|
}
|
||||||
|
|
||||||
|
test_sample!(day_09, Day09, 13, 1);
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod day_09_extended {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_part_2_bigger_sample() {
|
||||||
|
let input = vec![
|
||||||
|
Instruction {
|
||||||
|
direction: Direction::Right,
|
||||||
|
steps: 5,
|
||||||
|
},
|
||||||
|
Instruction {
|
||||||
|
direction: Direction::Up,
|
||||||
|
steps: 8,
|
||||||
|
},
|
||||||
|
Instruction {
|
||||||
|
direction: Direction::Left,
|
||||||
|
steps: 8,
|
||||||
|
},
|
||||||
|
Instruction {
|
||||||
|
direction: Direction::Down,
|
||||||
|
steps: 3,
|
||||||
|
},
|
||||||
|
Instruction {
|
||||||
|
direction: Direction::Right,
|
||||||
|
steps: 17,
|
||||||
|
},
|
||||||
|
Instruction {
|
||||||
|
direction: Direction::Down,
|
||||||
|
steps: 10,
|
||||||
|
},
|
||||||
|
Instruction {
|
||||||
|
direction: Direction::Left,
|
||||||
|
steps: 25,
|
||||||
|
},
|
||||||
|
Instruction {
|
||||||
|
direction: Direction::Up,
|
||||||
|
steps: 20,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
assert_eq!(Day09::part_2(&input), 36);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue