use nom::{ branch::alt, bytes::complete::tag, character::complete::{i32, line_ending}, combinator::{map, value}, multi::separated_list1, sequence::tuple, IResult, }; use std::{collections::BTreeSet, fs}; fn main() -> Result<(), Box> { let input = fs::read_to_string("inputs/day_9.txt")?; let movements = Movements::parser(&input).unwrap().1; let mut game_board_part_1 = GameBoard::new(2); for instruction in &movements.0 { game_board_part_1.step(instruction); } dbg!(game_board_part_1.tail_visited.len()); let mut game_board_part_2 = GameBoard::new(10); for instruction in &movements.0 { game_board_part_2.step(instruction); } dbg!(game_board_part_2.tail_visited.len()); Ok(()) } #[derive(Debug)] struct Movements(Vec); #[derive(Debug)] struct Instruction { direction: Direction, distance: i32, } #[derive(Debug, Clone, Copy)] enum Direction { Down, Up, Left, Right, } impl Movements { fn parser(input: &str) -> IResult<&str, Self> { map(separated_list1(line_ending, Instruction::parser), Movements)(input) } } impl Instruction { fn parser(input: &str) -> IResult<&str, Self> { map( tuple((Direction::parser, tag(" "), i32)), |(direction, _, distance)| Instruction { direction, distance, }, )(input) } } impl Direction { fn parser(input: &str) -> IResult<&str, Self> { alt(( value(Direction::Down, tag("D")), value(Direction::Up, tag("U")), value(Direction::Left, tag("L")), value(Direction::Right, tag("R")), ))(input) } } #[derive(Debug)] struct GameBoard { rope: Vec, tail_visited: BTreeSet, } #[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] struct Position { x: i32, y: i32, } impl GameBoard { fn new(length: usize) -> GameBoard { let mut tail_visited = BTreeSet::new(); tail_visited.insert(Position::default()); GameBoard { rope: vec![Position::default(); length], tail_visited, } } fn step(&mut self, instruction: &Instruction) { for _ in 0..instruction.distance { match instruction.direction { Direction::Down => self.rope[0].y -= 1, Direction::Up => self.rope[0].y += 1, Direction::Left => self.rope[0].x -= 1, Direction::Right => self.rope[0].x += 1, }; for tail_i in 1..self.rope.len() { let head_i = tail_i - 1; let head = self.rope[head_i].clone(); let tail = &mut self.rope[tail_i]; let tail_must_move = (head.x - tail.x).abs() > 1 || (head.y - tail.y).abs() > 1; if tail_must_move { if head.x > tail.x { tail.x += 1; } else if head.x < tail.x { tail.x -= 1; } if head.y > tail.y { tail.y += 1; } else if head.y < tail.y { tail.y -= 1; } } } self.tail_visited .insert(self.rope[self.rope.len() - 1].clone()); } } }