1
0

feat: solve day 12 part 1 & 2

This commit is contained in:
Rokas Puzonas 2021-12-27 16:23:53 +02:00
parent b0914ebb2b
commit d27f25036a
3 changed files with 187 additions and 0 deletions

24
input/12.txt Normal file
View File

@ -0,0 +1,24 @@
pf-pk
ZQ-iz
iz-NY
ZQ-end
pf-gx
pk-ZQ
ZQ-dc
NY-start
NY-pf
NY-gx
ag-ZQ
pf-start
start-gx
BN-ag
iz-pf
ag-FD
pk-NY
gx-pk
end-BN
ag-pf
iz-pk
pk-ag
iz-end
iz-BN

160
src/day12.rs Normal file
View File

@ -0,0 +1,160 @@
use std::collections::{HashMap, HashSet};
pub fn parse_input(input: &str) -> Vec<(String, String)> {
let mut edges: Vec<(String, String)> = Vec::new();
for line in input.lines() {
let (from, to) = line.split_once('-').unwrap();
edges.push((from.into(), to.into()));
}
return edges;
}
fn edges_to_map(edges: &Vec<(String, String)>) -> HashMap<String, Vec<String>> {
let mut map = HashMap::new();
for line in edges {
map.entry(line.1.clone())
.or_insert(Vec::new())
.push(line.0.clone());
map.entry(line.0.clone())
.or_insert(Vec::new())
.push(line.1.clone());
}
return map;
}
fn is_path_finished(path: &Vec<&str>) -> bool {
return path.contains(&"end")
}
fn can_be_appended_part1(path: &Vec<&str>, node: &str) -> bool {
node.to_uppercase() == node || !path.contains(&node)
}
pub fn part1(edges: &Vec<(String, String)>) -> usize {
let map = edges_to_map(edges);
let mut finished_paths: Vec<Vec<&str>> = Vec::new();
let mut unfinished_paths: Vec<Vec<&str>> = Vec::new();
unfinished_paths.push(vec!["start"]);
while unfinished_paths.len() > 0 {
let mut new_paths = Vec::new();
for path in &mut unfinished_paths {
for node in map.get(*path.last().unwrap()).unwrap() {
if can_be_appended_part1(path, node) {
let mut new_path = path.clone();
new_path.push(node);
if is_path_finished(&new_path) {
finished_paths.push(new_path);
} else {
new_paths.push(new_path);
}
}
}
}
unfinished_paths = new_paths;
}
return finished_paths.len();
}
fn can_be_appended_part2(path: &Vec<&str>, node: &str) -> bool {
if node == "start" { return false; }
if node == "end" { return true; }
if node.to_uppercase() == node { return true; }
// If all lowercase nodes only apear once we can be assure that any lowercase
// node that will be added will be correct.
let mut uniq = HashSet::new();
if path.into_iter().all(move |x| x.to_lowercase() != *x || uniq.insert(x)) {
return true;
}
return !path.contains(&node);
}
pub fn part2(edges: &Vec<(String, String)>) -> usize {
let map = edges_to_map(edges);
let mut finished_paths: Vec<Vec<&str>> = Vec::new();
let mut unfinished_paths: Vec<Vec<&str>> = Vec::new();
unfinished_paths.push(vec!["start"]);
while unfinished_paths.len() > 0 {
let mut new_paths = Vec::new();
for path in &mut unfinished_paths {
for node in map.get(*path.last().unwrap()).unwrap() {
if can_be_appended_part2(path, node) {
let mut new_path = path.clone();
new_path.push(node);
if is_path_finished(&new_path) {
finished_paths.push(new_path);
} else {
new_paths.push(new_path);
}
}
}
}
unfinished_paths = new_paths;
}
return finished_paths.len();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn part1_example() {
let cave_system = parse_input("start-A\nstart-b\nA-c\nA-b\nb-d\nA-end\nb-end");
let result = part1(&cave_system);
assert_eq!(result, 10);
}
#[test]
fn part1_larger_example() {
let cave_system = parse_input("dc-end\nHN-start\nstart-kj\ndc-start\ndc-HN\nLN-dc\nHN-end\nkj-sa\nkj-HN\nkj-dc");
let result = part1(&cave_system);
assert_eq!(result, 19);
}
#[test]
fn part1_largest_example() {
let cave_system = parse_input("fs-end\nhe-DX\nfs-he\nstart-DX\npj-DX\nend-zg\nzg-sl\nzg-pj\npj-he\nRW-he\nfs-DX\npj-RW\nzg-RW\nstart-pj\nhe-WI\nzg-he\npj-fs\nstart-RW");
let result = part1(&cave_system);
assert_eq!(result, 226);
}
#[test]
fn part2_example() {
let cave_system = parse_input("start-A\nstart-b\nA-c\nA-b\nb-d\nA-end\nb-end");
let result = part2(&cave_system);
assert_eq!(result, 36);
}
#[test]
fn part2_larger_example() {
let cave_system = parse_input("dc-end\nHN-start\nstart-kj\ndc-start\ndc-HN\nLN-dc\nHN-end\nkj-sa\nkj-HN\nkj-dc");
let result = part2(&cave_system);
assert_eq!(result, 103);
}
#[test]
fn part2_largest_example() {
let cave_system = parse_input("fs-end\nhe-DX\nfs-he\nstart-DX\npj-DX\nend-zg\nzg-sl\nzg-pj\npj-he\nRW-he\nfs-DX\npj-RW\nzg-RW\nstart-pj\nhe-WI\nzg-he\npj-fs\nstart-RW");
let result = part2(&cave_system);
assert_eq!(result, 3509);
}
}

View File

@ -9,6 +9,7 @@ mod day8;
mod day9;
mod day10;
mod day11;
mod day12;
use std::{env, process};
use std::fs::File;
@ -47,6 +48,8 @@ fn run(day: i32, part: i32, input_filename: &str) {
"10.2" => println!("{}", day10::part2(&day10::parse_input(&contents))),
"11.1" => println!("{}", day11::part1(&day11::parse_input(&contents))),
"11.2" => println!("{}", day11::part2(&day11::parse_input(&contents))),
"12.1" => println!("{}", day12::part1(&day12::parse_input(&contents))),
"12.2" => println!("{}", day12::part2(&day12::parse_input(&contents))),
_ => println!("Day {} part {} not found", day, part)
}
}