diff --git a/README.md b/README.md index b1b2740..9aeb6f6 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,9 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www. | [Day 13](./src/bin/13.rs) | `363.7µs` | `344.0µs` | | [Day 14](./src/bin/14.rs) | `245.3µs` | `127.9ms` | | [Day 15](./src/bin/15.rs) | `236.3µs` | `984.1µs` | +| [Day 16](./src/bin/16.rs) | `2.3ms` | `5.9ms` | -**Total: 594.95ms** +**Total: 603.15ms** --- diff --git a/data/examples/16.txt b/data/examples/16.txt new file mode 100644 index 0000000..2c21676 --- /dev/null +++ b/data/examples/16.txt @@ -0,0 +1,15 @@ +############### +#.......#....E# +#.#.###.#.###.# +#.....#.#...#.# +#.###.#####.#.# +#.#.#.......#.# +#.#.#####.###.# +#...........#.# +###.#.#####.#.# +#...#.....#.#.# +#.#.#.###.#.#.# +#.....#...#.#.# +#.###.#.#.#.#.# +#S..#.....#...# +############### diff --git a/src/bin/14.rs b/src/bin/14.rs index 24fe1f9..506f47f 100644 --- a/src/bin/14.rs +++ b/src/bin/14.rs @@ -3,6 +3,7 @@ use std::{ collections::{HashMap, HashSet}, }; +use pathfinding::matrix::directions::S; use regex::Regex; advent_of_code::solution!(14); @@ -76,30 +77,36 @@ pub fn part_two(input: &str) -> Option { robot.position.1 = robot.position.1.rem_euclid(height); } - let robot_positions: HashSet<(i32, i32)> = robots.iter().map(|r| r.position).collect(); - let symetric = robot_positions - .iter() - .filter(|(x, y)| robot_positions.contains(&(width - 1 - x, *y))) - .count(); - if symetric > symetric_max_count { - symetric_max_count = symetric; - seconds = i + 1; - // for y in 0..height { - // for x in 0..width { - // let mut found = false; - // for robot in robots.iter() { - // if robot.position == (x, y) { - // found = true; - // break; - // } - // } - // print!("{}", if found { '#' } else { '.' }); - // } - // println!(); - // } - // println!("Seconds: {}", i + 1); + let mut found = false; + let mut robot_positions: HashSet<(i32, i32)> = HashSet::new(); + for robot in robots.iter() { + if robot_positions.contains(&robot.position) { + found = true; + break; + } + robot_positions.insert(robot.position); + } + if found { + continue; } + seconds = i; + + for y in 0..height { + for x in 0..width { + let mut found = false; + for robot in robots.iter() { + if robot.position == (x, y) { + found = true; + break; + } + } + print!("{}", if found { '#' } else { '.' }); + } + println!(); + } + println!("Seconds: {}", i + 1); } + Some(seconds) } diff --git a/src/bin/16.rs b/src/bin/16.rs new file mode 100644 index 0000000..cf2dc7b --- /dev/null +++ b/src/bin/16.rs @@ -0,0 +1,104 @@ +advent_of_code::solution!(16); + +use itertools::Itertools; +use pathfinding::prelude::{astar, astar_bag}; + +const DIRS: [(i32, i32); 4] = [(-1, 0), (0, 1), (1, 0), (0, -1)]; + +fn in_bounds(map: &[Vec], pos: (i32, i32)) -> bool { + pos.0 >= 0 + && pos.1 >= 0 + && pos.0 < map.len() as i32 + && pos.1 < map[0].len() as i32 + && map[pos.0 as usize][pos.1 as usize] != '#' +} + +fn successors(map: &[Vec], node: &(i32, i32, i32)) -> Vec<((i32, i32, i32), u32)> { + let mut result = Vec::new(); + let dir = node.2 as usize; + let straight = (node.0 + DIRS[dir].0, node.1 + DIRS[dir].1); + if in_bounds(&map, straight) { + result.push(((straight.0, straight.1, node.2), 1)); + } + let left = ( + node.0 + DIRS[(dir + 3) % 4].0, + node.1 + DIRS[(dir + 3) % 4].1, + ); + if in_bounds(&map, left) { + result.push(((left.0, left.1, (node.2 + 3) % 4), 1001)); + } + let right = ( + node.0 + DIRS[(dir + 1) % 4].0, + node.1 + DIRS[(dir + 1) % 4].1, + ); + if in_bounds(&map, right) { + result.push(((right.0, right.1, (node.2 + 1) % 4), 1001)); + } + result +} + +fn parse_input(input: &str) -> (Vec>, (i32, i32, i32)) { + let map = input + .lines() + .map(|line| line.chars().collect::>()) + .collect::>(); + let mut start: (i32, i32, i32) = (0, 0, 0); + for (y, row) in map.iter().enumerate() { + for (x, cell) in row.iter().enumerate() { + if *cell == 'S' { + start = (y as i32, x as i32, 1); + } + } + } + (map, start) +} + +pub fn part_one(input: &str) -> Option { + let (map, start) = parse_input(input); + let res = astar( + &start, + |node| successors(&map, node), + |_| 0, + |node| map[node.0 as usize][node.1 as usize] == 'E', + ); + Some(res.unwrap().1 as u32) +} + +pub fn part_two(input: &str) -> Option { + let (map, start) = parse_input(input); + let res = astar_bag( + &start, + |node| successors(&map, node), + |_| 0, + |node| map[node.0 as usize][node.1 as usize] == 'E', + ); + Some( + res.unwrap() + .0 + .flat_map(|nodes| { + nodes + .iter() + .map(|node| (node.0, node.1)) + .collect::>() + }) + .unique() + .count() as u32, + ) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_part_one() { + let result = part_one(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some(7036)); + } + + #[test] + fn test_part_two() { + let result = part_two(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some(45)); + } +}