use std::env::args; use std::fs::File; use std::io::BufRead; use std::io::BufReader; fn split_once<'a>(s: &'a str, sep: &str) -> (&'a str, &'a str) { let i = s.find(sep).unwrap(); let left = &s[..i]; let right = &s[i+sep.len()..]; return (left, right); } fn encode(name: &str) -> u16 { // convert name to u16 because it can be copied easily if name == "start" { return 0; } else if name == "end" { return 1; } else { assert!(name.bytes().count() <= 3); let mut x: u16 = 0; if name.chars().next().unwrap().is_uppercase() { x |= 1; } for (i, b) in name.to_lowercase().bytes().enumerate() { // ord('a') = 97 // 24 possible chars -> 5 bits x |= ((b as u16) - 96) << (i * 5 + 1); } return x; } } fn walk(pos: u16, edges: &Vec<(u16, u16)>, visited: &Vec) -> u32 { if pos == 1 { return 1; } let mut v = visited.clone(); v.push(pos); let mut sum = 0; for (a, b) in edges { let other; if pos == *a { other = *b; } else if pos == *b { other = *a; } else { continue; } if other & 1 == 0 && visited.contains(&other) { continue; } sum += walk(other, edges, &v); } return sum; } fn main() { let path = args().nth(1).unwrap(); let file = File::open(path).unwrap(); let mut edges = vec![]; for line in BufReader::new(file).lines() { let l = line.unwrap(); let (left, right) = split_once(&l, "-"); edges.push((encode(left), encode(right))); } let sum = walk(0, &edges, &vec![]); print!("{}\n", sum); }