Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use std::io::{self, BufReader};
- use std::io::prelude::*;
- use std::fs::File;
- use std::collections::HashSet;
- fn read_file() -> Result<Vec<Vec<char>>, std::io::Error> {
- let file = File::open("input.txt")?;
- let reader = BufReader::new(file);
- let rows = reader
- .lines()
- .filter_map(Result::ok)
- .map(|line| line.chars().collect())
- .collect();
- Ok(rows)
- }
- fn find_position(input_map: &Vec<Vec<char>>) -> (isize, isize, char) {
- for (rowno, row) in input_map.iter().enumerate() {
- for (charno, character) in row.iter().enumerate() {
- if ['v', '>', '<', '^'].contains(character) {
- return (rowno as isize, charno as isize, *character);
- }
- }
- }
- (0, 0, 'x')
- }
- fn get_direction(symbol: char) -> (isize, isize) {
- match symbol {
- '>' => (0, 1),
- 'v' => (1, 0),
- '<' => (0, -1),
- '^' => (-1, 0),
- _ => (0, 0),
- }
- }
- fn get_next(symbol: char) -> char {
- match symbol {
- '>' => 'v',
- 'v' => '<',
- '<' => '^',
- '^' => '>',
- _ => 'x',
- }
- }
- fn navigate(input_map: &mut Vec<Vec<char>>, coords: (isize, isize), symbol: char) -> (u32, u32, isize, isize) {
- let mut acc = 0;
- let mut travel = 0;
- let (dir_x, dir_y) = get_direction(symbol);
- let (mut x, mut y) = coords;
- let (h, w) = (input_map.len(), input_map[0].len());
- let is_valid = |r: isize, c: isize| -> bool {
- r >= 0 && c >= 0 && (r as usize) < h && (c as usize) < w
- };
- loop {
- let new_x : isize = x + dir_x;
- let new_y : isize = y + dir_y;
- if is_valid(new_x, new_y)
- {
- match input_map[new_x as usize][new_y as usize] {
- '#' => {
- return (acc, travel, x, y);
- },
- 'X' => {
- x = new_x;
- y = new_y;
- travel += 1;
- }
- _ => {
- input_map[new_x as usize][new_y as usize] = 'X';
- acc += 1;
- travel += 1;
- x = new_x;
- y = new_y;
- }
- }
- }
- else {
- return (acc, travel, -1, -1);
- }
- }
- }
- fn part1() -> Result<u32, ()> {
- let mut acc = 1;
- let mut input_map = read_file().unwrap();
- let (mut x, mut y, mut symbol) = find_position(&input_map);
- // mark position as visited
- input_map[x as usize][y as usize] = 'X';
- loop {
- let (distance, _, new_x, new_y) = navigate(&mut input_map, (x, y), symbol);
- acc += distance;
- if new_x == -1 {
- break;
- }
- x = new_x;
- y = new_y;
- symbol = get_next(symbol);
- }
- Ok(acc)
- }
- fn part2() -> Result<u32, ()> {
- let mut acc = 0;
- let mut input_map = read_file().unwrap();
- let mut unique_obstacles : HashSet<(isize, isize)> = HashSet::new();
- let (init_x, init_y, mut symbol) = find_position(&input_map);
- let (h, w) = (input_map.len(), input_map[0].len());
- let is_valid = |r: isize, c: isize| -> bool {
- r >= 0 && c >= 0 && (r as usize) < h && (c as usize) < w
- };
- input_map[init_x as usize][init_y as usize] = 'X';
- // Current position while stepping
- let mut x = init_x;
- let mut y = init_y;
- loop {
- // Get direction according to symbol
- let (dir_x, dir_y) = get_direction(symbol);
- let step_x : isize = x + dir_x;
- let step_y : isize = y + dir_y;
- let mut checkpoints : HashSet<(isize, isize, char)> = HashSet::new();
- // Don't attempt to put a
- if step_x == init_x && step_y == init_y {
- x = step_x;
- y = step_y;
- continue;
- }
- if ! is_valid(step_x, step_y) {
- break;
- }
- match input_map[step_x as usize][step_y as usize] {
- // next field is an obstacle, so change direction
- '#' => {
- symbol = get_next(symbol);
- }
- 'X' => {
- // Already been here; cannot place a virtual obstacle if coming from a dif
- // direction
- x = step_x;
- y = step_y;
- }
- // next step is not an obstacle, so we'll check if a virtual obstacle results in a
- // loop
- '.' => {
- // placing virtual obstacle at step_x, step_y
- // add position and next direction to obstacle list
- let mut nav_x = x;
- let mut nav_y = y;
- let mut symb = get_next(symbol);
- // adding to list current x, current y and next dir
- checkpoints.insert((x, y, symb));
- input_map[nav_x as usize][nav_y as usize] = 'X';
- // attempt to navigate until exit or until travel is not 0, but distance is 0
- let mut cloned_map = input_map.clone();
- cloned_map[step_x as usize][step_y as usize] = '#';
- loop {
- let (distance, travel, new_x, new_y) = navigate(&mut cloned_map, (nav_x, nav_y), symb);
- if new_x == -1 {
- break;
- }
- /*
- if distance == 0 && travel != 0 {
- acc += 1;
- println!("Good obstacle at {} {} - travel {} distance {}, nav_x {} nav_y {}", step_x, step_y, travel, distance, nav_x, nav_y);
- break;
- }
- */
- symb = get_next(symb);
- if checkpoints.contains(&(new_x, new_y, symb)) {
- if ! unique_obstacles.contains(&(step_x, step_y)) {
- unique_obstacles.insert((step_x, step_y));
- acc +=1;
- println!("({}, {})", step_x, step_y);//, travel, distance, nav_x, nav_y);
- }
- break;
- }
- //
- checkpoints.insert((new_x, new_y, symb));
- nav_x = new_x;
- nav_y = new_y;
- }
- x = step_x;
- y = step_y;
- }
- _ => {println!("PANIC");}
- }
- }
- Ok(acc)
- }
- fn main() {
- let result1 = part1();
- println!("R1: {}", result1.unwrap());
- let result2 = part2();
- println!("R2: {}", result2.unwrap());
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement