Advertisement
Guest User

Untitled

a guest
Dec 10th, 2024
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 6.67 KB | None | 0 0
  1. use std::io::{self, BufReader};
  2. use std::io::prelude::*;
  3. use std::fs::File;
  4. use std::collections::HashSet;
  5.  
  6. fn read_file() -> Result<Vec<Vec<char>>, std::io::Error> {
  7.    
  8.     let file = File::open("input.txt")?;
  9.     let reader = BufReader::new(file);
  10.  
  11.     let rows = reader
  12.         .lines()
  13.         .filter_map(Result::ok)
  14.         .map(|line| line.chars().collect())
  15.         .collect();
  16.  
  17.  
  18.     Ok(rows)
  19. }
  20.  
  21. fn find_position(input_map: &Vec<Vec<char>>) -> (isize, isize, char) {
  22.     for (rowno, row) in input_map.iter().enumerate() {
  23.         for (charno, character) in row.iter().enumerate() {
  24.             if ['v', '>', '<', '^'].contains(character) {
  25.                 return (rowno as isize, charno as isize, *character);
  26.             }
  27.         }
  28.     }
  29.     (0, 0, 'x')
  30. }
  31.  
  32. fn get_direction(symbol: char) -> (isize, isize) {
  33.     match symbol {
  34.         '>' => (0, 1),
  35.         'v' => (1, 0),
  36.         '<' => (0, -1),
  37.         '^' => (-1, 0),
  38.         _ => (0, 0),
  39.     }
  40. }
  41.  
  42. fn get_next(symbol: char) -> char {
  43.     match symbol {
  44.         '>' => 'v',
  45.         'v' => '<',
  46.         '<' => '^',
  47.         '^' => '>',
  48.         _ => 'x',
  49.     }
  50. }
  51.  
  52.  
  53. fn navigate(input_map: &mut Vec<Vec<char>>, coords: (isize, isize), symbol: char) -> (u32, u32, isize, isize) {
  54.  
  55.     let mut acc = 0;
  56.     let mut travel = 0;
  57.     let (dir_x, dir_y) = get_direction(symbol);
  58.     let (mut x, mut y) = coords;
  59.  
  60.     let (h, w) = (input_map.len(), input_map[0].len());
  61.  
  62.     let is_valid = |r: isize, c: isize| -> bool {
  63.         r >= 0 && c >= 0 && (r as usize) < h && (c as usize) < w
  64.     };
  65.  
  66.     loop {
  67.         let new_x : isize = x + dir_x;
  68.         let new_y : isize = y + dir_y;
  69.  
  70.         if is_valid(new_x, new_y)
  71.         {
  72.             match input_map[new_x as usize][new_y as usize] {
  73.                 '#' => {
  74.                     return (acc, travel, x, y);
  75.                 },
  76.                 'X' => {
  77.                     x = new_x;
  78.                     y = new_y;
  79.                     travel += 1;
  80.                 }
  81.                 _ => {
  82.                     input_map[new_x as usize][new_y as usize] = 'X';
  83.                     acc += 1;
  84.                     travel += 1;
  85.                     x = new_x;
  86.                     y = new_y;
  87.                 }
  88.             }
  89.         }
  90.         else {
  91.             return (acc, travel, -1, -1);
  92.         }
  93.     }
  94. }
  95.  
  96. fn part1() -> Result<u32, ()> {
  97.  
  98.     let mut acc = 1;
  99.     let mut input_map = read_file().unwrap();
  100.  
  101.     let (mut x, mut y, mut symbol) = find_position(&input_map);
  102.     // mark position as visited
  103.     input_map[x as usize][y as usize] = 'X';
  104.     loop {
  105.         let (distance, _, new_x, new_y) = navigate(&mut input_map, (x, y), symbol);
  106.         acc += distance;
  107.         if new_x == -1 {
  108.             break;
  109.         }
  110.         x = new_x;
  111.         y = new_y;
  112.         symbol = get_next(symbol);
  113.     }
  114.  
  115.     Ok(acc)
  116. }
  117.  
  118. fn part2() -> Result<u32, ()> {
  119.    
  120.     let mut acc = 0;
  121.     let mut input_map = read_file().unwrap();
  122.  
  123.     let mut unique_obstacles : HashSet<(isize, isize)> = HashSet::new();
  124.  
  125.     let (init_x, init_y, mut symbol) = find_position(&input_map);
  126.    
  127.     let (h, w) = (input_map.len(), input_map[0].len());
  128.     let is_valid = |r: isize, c: isize| -> bool {
  129.         r >= 0 && c >= 0 && (r as usize) < h && (c as usize) < w
  130.     };
  131.     input_map[init_x as usize][init_y as usize] = 'X';
  132.  
  133.     // Current position while stepping
  134.     let mut x = init_x;
  135.     let mut y = init_y;
  136.  
  137.     loop {
  138.         // Get direction according to symbol
  139.         let (dir_x, dir_y) = get_direction(symbol);
  140.         let step_x : isize = x + dir_x;
  141.         let step_y : isize = y + dir_y;
  142.         let mut checkpoints : HashSet<(isize, isize, char)> = HashSet::new();
  143.  
  144.         // Don't attempt to put a
  145.         if step_x == init_x && step_y == init_y {
  146.             x = step_x;
  147.             y = step_y;
  148.             continue;
  149.         }
  150.  
  151.         if ! is_valid(step_x, step_y) {
  152.             break;
  153.         }
  154.  
  155.            
  156.         match input_map[step_x as usize][step_y as usize] {
  157.             // next field is an obstacle, so change direction
  158.             '#' => {
  159.                 symbol = get_next(symbol);
  160.             }
  161.             'X' => {
  162.                 // Already been here; cannot place a virtual obstacle if coming from a dif
  163.                 // direction
  164.                 x = step_x;
  165.                 y = step_y;
  166.             }
  167.             // next step is not an obstacle, so we'll check if a virtual obstacle results in a
  168.             // loop
  169.             '.' => {
  170.                 // placing virtual obstacle at step_x, step_y
  171.                 // add position and next direction to obstacle list
  172.                 let mut nav_x = x;
  173.                 let mut nav_y = y;
  174.                 let mut symb = get_next(symbol);
  175.                 // adding to list current x, current y and next dir
  176.                 checkpoints.insert((x, y, symb));
  177.                 input_map[nav_x as usize][nav_y as usize] = 'X';
  178.                 // attempt to navigate until exit or until travel is not 0, but distance is 0
  179.                 let mut cloned_map = input_map.clone();
  180.                 cloned_map[step_x as usize][step_y as usize] = '#';
  181.                 loop {
  182.                     let (distance, travel, new_x, new_y) = navigate(&mut cloned_map, (nav_x, nav_y), symb);
  183.                     if new_x == -1 {
  184.                         break;
  185.                     }
  186.                     /*
  187.                     if distance == 0 && travel != 0 {
  188.                         acc += 1;
  189.                         println!("Good obstacle at {} {} - travel {} distance {}, nav_x {} nav_y {}", step_x, step_y, travel, distance, nav_x, nav_y);
  190.                         break;
  191.                     }
  192.                     */
  193.                     symb = get_next(symb);
  194.                     if checkpoints.contains(&(new_x, new_y, symb))  {
  195.                         if ! unique_obstacles.contains(&(step_x, step_y)) {
  196.                             unique_obstacles.insert((step_x, step_y));
  197.                             acc +=1;
  198.                             println!("({}, {})", step_x, step_y);//, travel, distance, nav_x, nav_y);
  199.                         }
  200.                         break;
  201.                     }
  202.                     //
  203.                     checkpoints.insert((new_x, new_y, symb));
  204.                     nav_x = new_x;
  205.                     nav_y = new_y;
  206.                 }
  207.  
  208.                 x = step_x;
  209.                 y = step_y;
  210.  
  211.             }
  212.             _ => {println!("PANIC");}
  213.         }
  214.  
  215.     }
  216.  
  217.     Ok(acc)
  218. }
  219.  
  220. fn main() {
  221.     let result1 = part1();
  222.     println!("R1: {}", result1.unwrap());
  223.     let result2 = part2();
  224.     println!("R2: {}", result2.unwrap());
  225. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement