diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7b39dac..a472820 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -58,3 +58,8 @@ day-11: stage: build script: - cd day11; cargo run --release ./input + +day-12: + stage: build + script: + - cd day12; cargo run --release ./input diff --git a/day12/Cargo.toml b/day12/Cargo.toml new file mode 100644 index 0000000..ba13763 --- /dev/null +++ b/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/day12/input b/day12/input new file mode 100644 index 0000000..15f1102 --- /dev/null +++ b/day12/input @@ -0,0 +1,25 @@ +bm-XY +ol-JS +bm-im +RD-ol +bm-QI +JS-ja +im-gq +end-im +ja-ol +JS-gq +bm-AF +RD-start +RD-ja +start-ol +cj-bm +start-JS +AF-ol +end-QI +QI-gq +ja-gq +end-AF +im-QI +bm-gq +ja-QI +gq-RD diff --git a/day12/src/main.rs b/day12/src/main.rs new file mode 100644 index 0000000..b054c6e --- /dev/null +++ b/day12/src/main.rs @@ -0,0 +1,69 @@ +use std::{fs, env, collections::HashMap}; + +fn read_input(path: &str) -> String { + return fs::read_to_string(path).expect("Cannot read file."); +} + +fn parse_input(s: &str) -> HashMap> { + let mut m: HashMap> = HashMap::new(); + for l in s.lines() { + let t = l.split_once("-").unwrap(); + let mut i = m.get(t.0).unwrap_or(&vec![]).to_owned(); + let mut j = m.get(t.1).unwrap_or(&vec![]).to_owned(); + i.push(t.1.to_string()); + j.push(t.0.to_string()); + m.insert(t.0.to_string(), i); + m.insert(t.1.to_string(), j); + } + return m; +} + +fn is_small_cave(c: &str) -> bool { + if c == "start" || c == "end" { return false; } + return c.chars().fold(true, |acc, x| acc && x.is_lowercase()); +} + +fn are_all_under_x(p: &(Vec, HashMap), x: u32) -> bool { + for s in p.1.iter() { + if s.1 >= &x { return false; } + } + return true; +} + +fn build_paths(v: &HashMap>, c: &str, m: u32, p: &(Vec, HashMap)) -> Option, HashMap)>> { + if c == "end" { return Some(vec![(vec!["end".to_owned()], HashMap::new())]); } + + let is_smol = is_small_cave(c); + let mut res = vec![]; + for s in v.get(c).unwrap().iter() { + let mut path = p.clone(); + let count = *path.1.get(c).unwrap_or(&0); + if s == "start" || (is_smol && (count >= m || (m > 1 && count == m - 1 && !are_all_under_x(p, m)))) { continue; } + if is_smol { path.1.insert(c.to_string(), count + 1); } + path.0.push(s.to_string()); + if s == "end" { res.push(path); continue; } + + let sub = build_paths(v, s, m, &path); + for u in sub.unwrap_or(vec![]).iter() { + if u.0.last().unwrap_or(&"".to_string()) != "end" { continue; } + res.push(u.to_owned()); + } + } + return Some(res); +} + +fn main() { + let args: Vec = env::args().collect(); + for arg in args.iter().skip(1) { + let input = read_input(&arg); + let vec_in = parse_input(&input); + println!("[{}]", &arg); + println!("\t[Part 1] => Answer is '{}'.", + build_paths(&vec_in, "start", 1, &(vec!["start".to_owned()], HashMap::new())) + .unwrap_or(vec![]).len()); + println!("\t[Part 2] => Answer is '{}'.", + build_paths(&vec_in, "start", 2, &(vec!["start".to_owned()], HashMap::new())) + .unwrap_or(vec![]).len()); + } +} +