diff options
| -rw-r--r-- | src/bin/day15.rs | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/src/bin/day15.rs b/src/bin/day15.rs new file mode 100644 index 0000000..c55a3f1 --- /dev/null +++ b/src/bin/day15.rs @@ -0,0 +1,198 @@ +use std::collections::HashSet; + +static DAY: u8 = 15; + +fn main() { + let input = advent::read_lines(DAY); + println!("{DAY}a: {}", box_coordinates(&input)); + println!("{DAY}b: {}", 0); +} + +#[derive(Eq, PartialEq, Hash, Clone, Copy)] +struct Position { + x: isize, + y: isize, +} + +impl Position { + fn next(&self, direction: Direction) -> Position { + let (x, y) = match direction { + Direction::Up => (self.x, self.y - 1), + Direction::Down => (self.x, self.y + 1), + Direction::Left => (self.x - 1, self.y), + Direction::Right => (self.x + 1, self.y), + }; + Position { x, y } + } +} + +#[derive(Clone, Copy)] +enum Direction { + Up, + Down, + Left, + Right, +} + +impl Direction { + fn new(input: char) -> Direction { + match input { + '^' => Direction::Up, + 'v' => Direction::Down, + '<' => Direction::Left, + '>' => Direction::Right, + _ => unimplemented!(), + } + } +} + +struct Map { + floor: HashSet<Position>, + boxes: HashSet<Position>, + robot: Position, + directions: Vec<Direction>, +} + +impl Map { + fn new(input: &[String]) -> Map { + let mut floor = HashSet::new(); + let mut boxes = HashSet::new(); + let mut robot = Position { x: 0, y: 0 }; + let mut split_line = 0; + for (y, line) in input.iter().enumerate() { + if line.is_empty() { + split_line = y; + break; + } + for (x, c) in line.chars().enumerate() { + let pos = Position { x: x as isize, y: y as isize }; + match c { + '.' => { + floor.insert(pos); + }, + 'O' => { + floor.insert(pos); + boxes.insert(pos); + }, + '@' => { + floor.insert(pos); + robot = pos; + }, + _ => {} + } + } + } + let mut directions = Vec::new(); + for line in input.iter().skip(split_line) { + for direction in line.chars().map(Direction::new) { + directions.push(direction); + } + } + Map { floor, boxes, robot, directions } + } + + fn _print_map(&self) { + let max_x = self.floor.iter().map(|pos| pos.x).max().unwrap(); + let max_y = self.floor.iter().map(|pos| pos.y).max().unwrap(); + for y in 0 ..= max_y { + for x in 0 ..= max_x { + let pos = Position { x, y }; + if self.robot == pos { + print!("@"); + } else if self.boxes.contains(&pos) { + print!("O"); + } else if self.floor.contains(&pos) { + print!("."); + } else { + print!("#"); + } + } + println!(); + } + println!(); + } + + fn coordinates(&self) -> isize { + self.boxes.iter() + .map(|pos| pos.y * 100 + pos.x) + .sum() + } + + fn move_to(&mut self, pos: &Position, direction: Direction) -> bool { + if !self.floor.contains(pos) { + return false; + } + if self.boxes.contains(pos) { + let next_pos = pos.next(direction); + if self.move_to(&next_pos, direction) { + self.boxes.remove(pos); + self.boxes.insert(next_pos); + } else { + return false; + } + } + true + } + + fn move_robot(&mut self) { + for direction in self.directions.clone().iter() { + let next_pos = self.robot.next(*direction); + if self.move_to(&next_pos, *direction) { + self.robot = next_pos; + } + } + } +} + +fn box_coordinates(input: &[String]) -> isize { + let mut map = Map::new(input); + map.move_robot(); + map.coordinates() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test() { + let input = [ + "########", + "#..O.O.#", + "##@.O..#", + "#...O..#", + "#.#.O..#", + "#...O..#", + "#......#", + "########", + "", + "<^^>>>vv<v>>v<<", + ].iter().map(|&x| String::from(x)).collect::<Vec<_>>(); + assert_eq!(box_coordinates(&input), 2028); + + let input = [ + "##########", + "#..O..O.O#", + "#......O.#", + "#.OO..O.O#", + "#..O@..O.#", + "#O#..O...#", + "#O..O..O.#", + "#.OO.O.OO#", + "#....O...#", + "##########", + "", + "<vv>^<v^>v>^vv^v>v<>v^v<v<^vv<<<^><<><>>v<vvv<>^v^>^<<<><<v<<<v^vv^v>^", + "vvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<<v<^v>^<^^>>>^<v<v", + "><>vv>v^v^<>><>>>><^^>vv>v<^^^>>v^v^<^^>v^^>v^<^v>v<>>v^v^<v>v^^<^^vv<", + "<<v<^>>^^^^>>>v^<>vvv^><v<<<>^^^vv^<vvv>^>v<^^^^v<>^>vvvv><>>v^<<^^^^^", + "^><^><>>><>^^<<^^v>>><^<v>^<vv>>v>>>^v><>^v><<<<v>>v<v<v>vvv>^<><<>^><", + "^>><>^v<><^vvv<^^<><v<<<<<><^v<<<><<<^^<v<^^^><^>>^<v^><<<^>>^v<v^v<v^", + ">^>>^v>vv>^<<^v<>><<><<v<<v><>v<^vv<<<>^^v^>^^>>><<^v>>v^v><^^>>^<>vv^", + "<><^^>^^^<><vvvvv^v<v<<>^v<v>v<<^><<><<><<<^^<<<^<<>><<><^^^>^^<>^>v<>", + "^^>vv<^v^v<vv>^<><v<^v>^^^>>>^^vvv^>vvv<>>>^<^>>>>>^<<^v>^vvv<>^<><<v>", + "v^^>>><<^^<>>^v^<v^vv<>v^<<>^<^v^v><^<<<><<^<v><v<>vv>>v><v^<vv<>v^<<^", + ].iter().map(|&x| String::from(x)).collect::<Vec<_>>(); + assert_eq!(box_coordinates(&input), 10092); + } +} |
