diff --git a/2021/day12/Cargo.lock b/2021/day12/Cargo.lock new file mode 100644 index 0000000..5e9bbe3 --- /dev/null +++ b/2021/day12/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "day12" +version = "0.1.0" diff --git a/2021/day12/Cargo.toml b/2021/day12/Cargo.toml new file mode 100644 index 0000000..ba13763 --- /dev/null +++ b/2021/day12/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "day12" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/2021/day12/README.md b/2021/day12/README.md new file mode 100644 index 0000000..0b90f69 --- /dev/null +++ b/2021/day12/README.md @@ -0,0 +1,146 @@ +https://adventofcode.com/2021/day/12 + +## \--- Day 12: Passage Pathing --- + +With your submarine's subterranean subsystems subsisting suboptimally, the +only way you're getting out of this cave anytime soon is by finding a path +yourself. Not just _a_ path - the only way to know if you've found the _best_ +path is to find _all_ of them. + +Fortunately, the sensors are still mostly working, and so you build a rough +map of the remaining caves (your puzzle input). For example: + +[code] + + start-A + start-b + A-c + A-b + b-d + A-end + b-end + +[/code] + +This is a list of how all of the caves are connected. You start in the cave +named `start`, and your destination is the cave named `end`. An entry like +`b-d` means that cave `b` is connected to cave `d` \- that is, you can move +between them. + +So, the above cave system looks roughly like this: + +[code] + + start + / \ + c--A-----b--d + \ / + end + +[/code] + +Your goal is to find the number of distinct _paths_ that start at `start`, end +at `end`, and don't visit small caves more than once. There are two types of +caves: _big_ caves (written in uppercase, like `A`) and _small_ caves (written +in lowercase, like `b`). It would be a waste of time to visit any small cave +more than once, but big caves are large enough that it might be worth visiting +them multiple times. So, all paths you find should _visit small caves at most +once_ , and can _visit big caves any number of times_. + +Given these rules, there are `_10_` paths through this example cave system: + +[code] + + start,A,b,A,c,A,end + start,A,b,A,end + start,A,b,end + start,A,c,A,b,A,end + start,A,c,A,b,end + start,A,c,A,end + start,A,end + start,b,A,c,A,end + start,b,A,end + start,b,end + +[/code] + +(Each line in the above list corresponds to a single path; the caves visited +by that path are listed in the order they are visited and separated by +commas.) + +Note that in this cave system, cave `d` is never visited by any path: to do +so, cave `b` would need to be visited twice (once on the way to cave `d` and a +second time when returning from cave `d`), and since cave `b` is small, this +is not allowed. + +Here is a slightly larger example: + +[code] + + dc-end + HN-start + start-kj + dc-start + dc-HN + LN-dc + HN-end + kj-sa + kj-HN + kj-dc + +[/code] + +The `19` paths through it are as follows: + +[code] + + start,HN,dc,HN,end + start,HN,dc,HN,kj,HN,end + start,HN,dc,end + start,HN,dc,kj,HN,end + start,HN,end + start,HN,kj,HN,dc,HN,end + start,HN,kj,HN,dc,end + start,HN,kj,HN,end + start,HN,kj,dc,HN,end + start,HN,kj,dc,end + start,dc,HN,end + start,dc,HN,kj,HN,end + start,dc,end + start,dc,kj,HN,end + start,kj,HN,dc,HN,end + start,kj,HN,dc,end + start,kj,HN,end + start,kj,dc,HN,end + start,kj,dc,end + +[/code] + +Finally, this even larger example has `226` paths through it: + +[code] + + fs-end + he-DX + fs-he + start-DX + pj-DX + end-zg + zg-sl + zg-pj + pj-he + RW-he + fs-DX + pj-RW + zg-RW + start-pj + he-WI + zg-he + pj-fs + start-RW + +[/code] + +_How many paths through this cave system are there that visit small caves at +most once?_ + diff --git a/2021/day12/input/example0 b/2021/day12/input/example0 new file mode 100644 index 0000000..6fd8c41 --- /dev/null +++ b/2021/day12/input/example0 @@ -0,0 +1,7 @@ +start-A +start-b +A-c +A-b +b-d +A-end +b-end diff --git a/2021/day12/input/example1 b/2021/day12/input/example1 new file mode 100644 index 0000000..7048cd5 --- /dev/null +++ b/2021/day12/input/example1 @@ -0,0 +1,5 @@ + start + / \ +c--A-----b--d + \ / + end diff --git a/2021/day12/input/example2 b/2021/day12/input/example2 new file mode 100644 index 0000000..ef84176 --- /dev/null +++ b/2021/day12/input/example2 @@ -0,0 +1,10 @@ +start,A,b,A,c,A,end +start,A,b,A,end +start,A,b,end +start,A,c,A,b,A,end +start,A,c,A,b,end +start,A,c,A,end +start,A,end +start,b,A,c,A,end +start,b,A,end +start,b,end diff --git a/2021/day12/input/example3 b/2021/day12/input/example3 new file mode 100644 index 0000000..62cc714 --- /dev/null +++ b/2021/day12/input/example3 @@ -0,0 +1,10 @@ +dc-end +HN-start +start-kj +dc-start +dc-HN +LN-dc +HN-end +kj-sa +kj-HN +kj-dc diff --git a/2021/day12/input/example4 b/2021/day12/input/example4 new file mode 100644 index 0000000..bbafd51 --- /dev/null +++ b/2021/day12/input/example4 @@ -0,0 +1,19 @@ +start,HN,dc,HN,end +start,HN,dc,HN,kj,HN,end +start,HN,dc,end +start,HN,dc,kj,HN,end +start,HN,end +start,HN,kj,HN,dc,HN,end +start,HN,kj,HN,dc,end +start,HN,kj,HN,end +start,HN,kj,dc,HN,end +start,HN,kj,dc,end +start,dc,HN,end +start,dc,HN,kj,HN,end +start,dc,end +start,dc,kj,HN,end +start,kj,HN,dc,HN,end +start,kj,HN,dc,end +start,kj,HN,end +start,kj,dc,HN,end +start,kj,dc,end diff --git a/2021/day12/input/example5 b/2021/day12/input/example5 new file mode 100644 index 0000000..65f3833 --- /dev/null +++ b/2021/day12/input/example5 @@ -0,0 +1,18 @@ +fs-end +he-DX +fs-he +start-DX +pj-DX +end-zg +zg-sl +zg-pj +pj-he +RW-he +fs-DX +pj-RW +zg-RW +start-pj +he-WI +zg-he +pj-fs +start-RW diff --git a/2021/day12/input/input b/2021/day12/input/input new file mode 100644 index 0000000..00a5183 --- /dev/null +++ b/2021/day12/input/input @@ -0,0 +1,25 @@ +fw-ll +end-dy +tx-fw +tx-tr +dy-jb +ZD-dy +dy-BL +dy-tr +dy-KX +KX-start +KX-tx +fw-ZD +tr-end +fw-jb +fw-yi +ZD-nr +start-fw +tx-ll +ll-jb +yi-jb +yi-ll +yi-start +ZD-end +ZD-jb +tx-ZD diff --git a/2021/day12/src/main.rs b/2021/day12/src/main.rs new file mode 100644 index 0000000..5aa1eda --- /dev/null +++ b/2021/day12/src/main.rs @@ -0,0 +1,144 @@ +use std::collections::HashMap; +use std::collections::HashSet; +use std::io::stdin; +use std::io::BufRead; + +fn main() { + println!("Hello, world!"); + let arg = std::env::args().nth(1).unwrap_or_else(String::new); + match arg.as_str() { + "part1" => part1(), + _ => part2(), + } +} + +fn part1() { + println!("Part1"); + + let mut map: HashMap> = HashMap::new(); + + for line in stdin().lock().lines() { + let line = line.unwrap(); + println!("{}", line); + let mut parts = line.split('-'); + let cave_a = parts.next().unwrap().to_string(); + let cave_b = parts.next().unwrap().to_string(); + + let cave_a_connections = map.entry(cave_a.clone()).or_insert_with(Vec::new); + cave_a_connections.push(cave_b.clone()); + + let cave_b_connections = map.entry(cave_b.clone()).or_insert_with(Vec::new); + cave_b_connections.push(cave_a); + } + + println!("{:?}", map); + + let mut incomplete_paths = Vec::new(); + let mut paths = Vec::new(); + + incomplete_paths.push(vec!["start".to_string()]); + + while !incomplete_paths.is_empty() { + let path = incomplete_paths.pop().unwrap(); + let last_cave = path.last().unwrap(); + + let options = map.get(last_cave).unwrap(); + + for option in options { + let first_char = option.chars().next().unwrap(); + if first_char.is_lowercase() { + let has_been_visited = path.iter().any(|cave| cave == option); + if has_been_visited { + continue; + } + } + let mut new_path = path.clone(); + new_path.push(option.clone()); + + if option == "end" { + paths.push(new_path); + } else { + incomplete_paths.push(new_path); + } + } + } + + for path in paths.iter() { + println!("{:?}", path); + } + + let path_count = paths.len(); + dbg!(path_count); +} + +fn part2() { + println!("Part2"); + + let mut map: HashMap> = HashMap::new(); + + for line in stdin().lock().lines() { + let line = line.unwrap(); + println!("{}", line); + let mut parts = line.split('-'); + let cave_a = parts.next().unwrap().to_string(); + let cave_b = parts.next().unwrap().to_string(); + + let cave_a_connections = map.entry(cave_a.clone()).or_insert_with(Vec::new); + cave_a_connections.push(cave_b.clone()); + + let cave_b_connections = map.entry(cave_b.clone()).or_insert_with(Vec::new); + cave_b_connections.push(cave_a); + } + + println!("{:?}", map); + + let mut incomplete_paths = Vec::new(); + let mut paths = Vec::new(); + + incomplete_paths.push(vec!["start".to_string()]); + + while !incomplete_paths.is_empty() { + let path = incomplete_paths.pop().unwrap(); + let last_cave = path.last().unwrap(); + + let options = map.get(last_cave).unwrap(); + + for option in options { + let first_char = option.chars().next().unwrap(); + + if option == "start" { + continue; + } + if first_char.is_lowercase() { + let has_been_visited = path.iter().any(|cave| cave == option); + let mut visited_small_caves = path + .iter() + .filter(|cave| cave.chars().next().unwrap().is_lowercase()) + .collect::>(); + let count_small_caves = visited_small_caves.len(); + visited_small_caves.sort(); + visited_small_caves.dedup(); + let count_unique_small_caves = visited_small_caves.len(); + let is_any_small_cave_visited_twice = count_small_caves != count_unique_small_caves; + if is_any_small_cave_visited_twice && has_been_visited { + continue; + } + } + let mut new_path = path.clone(); + new_path.push(option.clone()); + + if option == "end" { + paths.push(new_path); + } else { + incomplete_paths.push(new_path); + } + } + } + + for path in paths.iter() { + println!("{:?}", path); + } + + let path_count = paths.len(); + dbg!(path_count); +}