Advertisement
saaoijeefhiuh

day 17

Dec 17th, 2023
59
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 3.18 KB | None | 0 0
  1. advent_of_code::solution!(17);
  2. use std::cmp::{max, min};
  3.  
  4. use std::collections::{HashMap, VecDeque};
  5.  
  6. #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
  7. enum Dir {
  8.     H,
  9.     V,
  10. }
  11.  
  12. #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
  13. struct Loc {
  14.     i: i32,
  15.     j: i32,
  16.     dir: Dir,
  17. }
  18.  
  19. fn solve(input: &str, min_move: i32, max_move: i32) -> Option<u32> {
  20.     let h = input.lines().count();
  21.     let w = input.lines().next()?.chars().count();
  22.  
  23.     let map: Vec<Vec<u32>> = input
  24.         .lines()
  25.         .map(|line| line.chars().filter_map(|c| c.to_digit(10)).collect())
  26.         .collect();
  27.  
  28.     let mut queue: VecDeque<Loc> = VecDeque::from([
  29.         Loc { i: 0, j: 0, dir: Dir::H },
  30.         Loc { i: 0, j: 0, dir: Dir::V },
  31.     ]);
  32.  
  33.     let mut visited: HashMap<Loc, u32> = HashMap::from([(queue[0], 0), (queue[1], 0)]);
  34.  
  35.     while queue.len() > 0 {
  36.         let p = queue.pop_front().unwrap();
  37.         let loss = visited[&p];
  38.  
  39.         let search = |a, b| if a < b { (a + 1)..(b + 1) } else { b..a };
  40.  
  41.         // generate each of the possible moves from current location / direction
  42.         match p.dir {
  43.             Dir::H => (max(p.i - max_move, 0)..min(p.i + 1 + max_move, h as i32))
  44.                 .filter(|&i| (p.i - i).abs() >= min_move)
  45.                 .map(|i| {
  46.                     (
  47.                         loss + search(i, p.i)
  48.                             .map(|ii| map[ii as usize][p.j as usize])
  49.                             .sum::<u32>(),
  50.                         Loc { i: i, j: p.j, dir: Dir::V },
  51.                     )
  52.                 })
  53.                 .collect::<Vec<(u32, Loc)>>(),
  54.             Dir::V => (max(p.j - max_move, 0)..min(p.j + 1 + max_move, w as i32))
  55.                 .filter(|&j| (p.j - j).abs() >= min_move)
  56.                 .map(|j| {
  57.                     (
  58.                         loss + search(j, p.j)
  59.                             .map(|jj| map[p.i as usize][jj as usize])
  60.                             .sum::<u32>(),
  61.                         Loc { i: p.i, j: j, dir: Dir::H },
  62.                     )
  63.                 })
  64.                 .collect::<Vec<(u32, Loc)>>(),
  65.         }
  66.         .iter()
  67.         // store each new, and improved, move
  68.         .for_each(|(next_loss, loc)| {
  69.             visited
  70.                 .entry(*loc)
  71.                 .and_modify(|e| {
  72.                     if *next_loss < *e {
  73.                         *e = *next_loss;
  74.                         if !queue.contains(loc) {
  75.                             queue.push_back(*loc);
  76.                         }
  77.                     }
  78.                 })
  79.                 .or_insert_with(|| {
  80.                     queue.push_back(*loc);
  81.                     *next_loss
  82.                 });
  83.         });
  84.     }
  85.  
  86.     // find the best direction that ended up at the final position
  87.     [Dir::V, Dir::H]
  88.         .iter()
  89.         .filter_map(|&d| {
  90.             visited.get(&Loc {
  91.                 i: (h - 1) as i32,
  92.                 j: (w - 1) as i32,
  93.                 dir: d,
  94.             })
  95.         })
  96.         .min()
  97.         .copied()
  98. }
  99.  
  100. pub fn part_one(input: &str) -> Option<u32> {
  101.     solve(input, 1, 3)
  102. }
  103.  
  104. pub fn part_two(input: &str) -> Option<u32> {
  105.     solve(input, 4, 10)
  106. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement