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);
|
advent_of_code::solution!(23);
|
||||||
|
|
||||||
pub fn part_one(input: &str) -> Option<u32> {
|
use std::collections::{HashMap, HashSet};
|
||||||
None
|
|
||||||
|
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
|
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)]
|
#[cfg(test)]
|
||||||
|
@ -15,12 +203,12 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_part_one() {
|
fn test_part_one() {
|
||||||
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
|
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
|
||||||
assert_eq!(result, None);
|
assert_eq!(result, Some(94));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_part_two() {
|
fn test_part_two() {
|
||||||
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
|
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