day 23 solution
parent
5054b1b498
commit
c6ca78cbef
|
@ -0,0 +1,23 @@
|
|||
#.#####################
|
||||
#.......#########...###
|
||||
#######.#########.#.###
|
||||
###.....#.>.>.###.#.###
|
||||
###v#####.#v#.###.#.###
|
||||
###.>...#.#.#.....#...#
|
||||
###v###.#.#.#########.#
|
||||
###...#.#.#.......#...#
|
||||
#####.#.#.#######.#.###
|
||||
#.....#.#.#.......#...#
|
||||
#.#####.#.#.#########v#
|
||||
#.#...#...#...###...>.#
|
||||
#.#.#v#######v###.###v#
|
||||
#...#.>.#...>.>.#.###.#
|
||||
#####v#.#.###v#.#.###.#
|
||||
#.....#...#...#.#.#...#
|
||||
#.#########.###.#.#.###
|
||||
#...###...#...#...#.###
|
||||
###.###.#.###v#####v###
|
||||
#...#...#.#.>.>.#.>.###
|
||||
#.###.###.#.###.#.#v###
|
||||
#.....###...###...#...#
|
||||
#####################.#
|
|
@ -1,11 +1,199 @@
|
|||
advent_of_code::solution!(23);
|
||||
|
||||
pub fn part_one(input: &str) -> Option<u32> {
|
||||
None
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
struct Map {
|
||||
m: [[char; 141]; 141],
|
||||
width: usize,
|
||||
height: usize,
|
||||
}
|
||||
|
||||
pub fn part_two(input: &str) -> Option<u32> {
|
||||
type Coord = (usize, usize);
|
||||
|
||||
fn parse(input: &str) -> Map {
|
||||
let mut m = [[' '; 141]; 141];
|
||||
let mut width = 0;
|
||||
let mut height = 0;
|
||||
for (x, line) in input.lines().enumerate() {
|
||||
for (y, char) in line.chars().enumerate() {
|
||||
m[x][y] = char;
|
||||
width = y;
|
||||
}
|
||||
height = x;
|
||||
}
|
||||
Map { m, width, height }
|
||||
}
|
||||
|
||||
fn find_path(map: &Map, start: Coord, path: &HashSet<Coord>) -> Option<usize> {
|
||||
let mut p = path.clone();
|
||||
let mut cur = start.clone();
|
||||
loop {
|
||||
p.insert(cur);
|
||||
let mut next: Vec<Coord> = vec![];
|
||||
let c = map.m[cur.0][cur.1];
|
||||
if c == '>' {
|
||||
next.push((cur.0, cur.1 + 1));
|
||||
} else if c == '<' {
|
||||
next.push((cur.0, cur.1 - 1));
|
||||
} else if c == 'v' {
|
||||
next.push((cur.0 + 1, cur.1));
|
||||
} else {
|
||||
if cur.1 > 0 {
|
||||
let lcoord = (cur.0, cur.1 - 1);
|
||||
let l = map.m[lcoord.0][lcoord.1];
|
||||
if !p.contains(&lcoord) && l != '#' && l != '>' {
|
||||
next.push(lcoord);
|
||||
}
|
||||
}
|
||||
if cur.1 < map.width - 1 {
|
||||
let rcoord = (cur.0, cur.1 + 1);
|
||||
let r = map.m[rcoord.0][rcoord.1];
|
||||
if !p.contains(&rcoord) && r != '#' {
|
||||
next.push(rcoord);
|
||||
}
|
||||
}
|
||||
if cur.0 > 0 {
|
||||
let ucoord = (cur.0 - 1, cur.1);
|
||||
let u = map.m[ucoord.0][ucoord.1];
|
||||
if !p.contains(&ucoord) && u != '#' && u != 'v' {
|
||||
next.push(ucoord);
|
||||
}
|
||||
}
|
||||
if cur.0 <= map.height - 1 {
|
||||
let dcoord = (cur.0 + 1, cur.1);
|
||||
let d = map.m[dcoord.0][dcoord.1];
|
||||
if !p.contains(&dcoord) && d != '#' {
|
||||
next.push(dcoord);
|
||||
}
|
||||
}
|
||||
}
|
||||
if next.is_empty() {
|
||||
return None;
|
||||
} else if next.len() == 1 {
|
||||
cur = next[0];
|
||||
} else {
|
||||
return next.iter().filter_map(|k| find_path(map, *k, &p)).max();
|
||||
}
|
||||
if cur.0 == map.height {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Some(p.len())
|
||||
}
|
||||
|
||||
pub fn part_one(input: &str) -> Option<usize> {
|
||||
let map = parse(input);
|
||||
find_path(&map, (0, 1), &HashSet::new())
|
||||
}
|
||||
|
||||
type Graph = HashMap<Coord, HashMap<Coord, usize>>;
|
||||
|
||||
fn to_graph(map: &Map, initial: Coord, start: Coord, r: &mut Graph) {
|
||||
if !r.contains_key(&initial) {
|
||||
r.insert(initial, HashMap::new());
|
||||
}
|
||||
let mut v: HashSet<Coord> = HashSet::new();
|
||||
v.insert(initial);
|
||||
let mut cur = start.clone();
|
||||
let mut steps = 1;
|
||||
if initial.0 == 0 && initial.1 == 1 {
|
||||
steps -= 1;
|
||||
}
|
||||
loop {
|
||||
let mut next: Vec<Coord> = vec![];
|
||||
v.insert(cur);
|
||||
if cur.1 > 0 {
|
||||
let lcoord = (cur.0, cur.1 - 1);
|
||||
let l = map.m[lcoord.0][lcoord.1];
|
||||
if l != '#' {
|
||||
next.push(lcoord);
|
||||
}
|
||||
}
|
||||
if cur.1 <= map.width - 1 {
|
||||
let rcoord = (cur.0, cur.1 + 1);
|
||||
let r = map.m[rcoord.0][rcoord.1];
|
||||
if r != '#' {
|
||||
next.push(rcoord);
|
||||
}
|
||||
}
|
||||
if cur.0 > 0 {
|
||||
let ucoord = (cur.0 - 1, cur.1);
|
||||
let u = map.m[ucoord.0][ucoord.1];
|
||||
if u != '#' {
|
||||
next.push(ucoord);
|
||||
}
|
||||
}
|
||||
if cur.0 <= map.height - 1 {
|
||||
let dcoord = (cur.0 + 1, cur.1);
|
||||
let d = map.m[dcoord.0][dcoord.1];
|
||||
if d != '#' {
|
||||
next.push(dcoord);
|
||||
}
|
||||
}
|
||||
if next.len() > 2 {
|
||||
let parent = r.get_mut(&initial).unwrap();
|
||||
if parent.contains_key(&cur) {
|
||||
return;
|
||||
} else {
|
||||
parent.insert(cur, steps);
|
||||
for x in next.iter() {
|
||||
to_graph(map, cur, *x, r);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let Some(next_spot) = next.iter().find(|n| !v.contains(*n)) {
|
||||
steps += 1;
|
||||
cur = *next_spot;
|
||||
} else {
|
||||
let parent = r.get_mut(&initial).unwrap();
|
||||
if !parent.contains_key(&cur) {
|
||||
parent.insert(cur, steps);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn dfs(
|
||||
g: &Graph,
|
||||
steps: usize,
|
||||
cur: Coord,
|
||||
dest: Coord,
|
||||
visited: &mut HashSet<Coord>,
|
||||
) -> Option<usize> {
|
||||
if cur == dest {
|
||||
return Some(steps);
|
||||
}
|
||||
let neighbors = g.get(&cur).unwrap();
|
||||
visited.insert(cur);
|
||||
let m = neighbors
|
||||
.iter()
|
||||
.filter_map(|(n, dist)| {
|
||||
if visited.contains(&n) {
|
||||
None
|
||||
} else if *n == dest {
|
||||
Some(steps + dist)
|
||||
} else {
|
||||
dfs(g, steps + dist, *n, dest, visited)
|
||||
}
|
||||
})
|
||||
.max();
|
||||
visited.remove(&cur);
|
||||
m
|
||||
}
|
||||
|
||||
pub fn part_two(input: &str) -> Option<usize> {
|
||||
let map = parse(input);
|
||||
let mut g: Graph = HashMap::new();
|
||||
to_graph(&map, (0, 1), (0, 1), &mut g);
|
||||
dfs(
|
||||
&g,
|
||||
0,
|
||||
(0, 1),
|
||||
(map.height, map.width - 1),
|
||||
&mut HashSet::new(),
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -15,12 +203,12 @@ mod tests {
|
|||
#[test]
|
||||
fn test_part_one() {
|
||||
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
|
||||
assert_eq!(result, None);
|
||||
assert_eq!(result, Some(94));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_part_two() {
|
||||
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
|
||||
assert_eq!(result, None);
|
||||
assert_eq!(result, Some(154));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue