diff --git a/input/day14 b/input/day14 new file mode 100644 index 0000000..2206bc4 --- /dev/null +++ b/input/day14 @@ -0,0 +1,102 @@ +OHFNNCKCVOBHSSHONBNF + +SV -> O +KP -> H +FP -> B +VP -> V +KN -> S +KS -> O +SB -> K +BS -> K +OF -> O +ON -> S +VS -> F +CK -> C +FB -> K +CH -> K +HS -> H +PO -> F +NP -> N +FH -> C +FO -> O +FF -> C +CO -> K +NB -> V +PP -> S +BB -> N +HH -> B +KK -> H +OP -> K +OS -> V +KV -> F +VH -> F +OB -> S +CN -> H +SF -> K +SN -> P +NF -> H +HB -> V +VC -> S +PS -> P +NK -> B +CV -> P +BC -> S +NH -> K +FN -> P +SH -> F +FK -> P +CS -> O +VV -> H +OC -> F +CC -> N +HK -> N +FS -> P +VF -> B +SS -> V +PV -> V +BF -> V +OV -> C +HO -> F +NC -> F +BN -> F +HC -> N +KO -> P +KH -> F +BV -> S +SK -> F +SC -> F +VN -> V +VB -> V +BH -> O +CP -> K +PK -> K +PB -> K +FV -> S +HN -> K +PH -> B +VK -> B +PC -> H +BO -> H +SP -> V +NS -> B +OH -> N +KC -> H +HV -> F +HF -> B +HP -> S +CB -> P +PN -> S +BK -> K +PF -> N +SO -> P +CF -> B +VO -> C +OO -> K +FC -> F +NV -> F +OK -> K +NN -> O +NO -> O +BP -> O +KB -> O +KF -> O \ No newline at end of file diff --git a/src/day11.rs b/src/day11.rs index 2db219b..e240521 100644 --- a/src/day11.rs +++ b/src/day11.rs @@ -69,10 +69,8 @@ fn do_flash(mut hm: &mut FlashMap, mut flashing: &mut Vec<(i32, i32)>, mut flash for yn in (y - 1)..=(y + 1) { if let Some(e) = hm.get_mut(&(xn, yn)) { *e += 1; - if *e > 9 { - if !flashed.contains(&(xn, yn)) && !flashing.contains(&(xn, yn)) { - flashing.push((xn, yn)) - } + if *e > 9 && !flashed.contains(&(xn, yn)) && !flashing.contains(&(xn, yn)) { + flashing.push((xn, yn)) } } } diff --git a/src/day12.rs b/src/day12.rs index 7a4ce96..8f4e1fd 100644 --- a/src/day12.rs +++ b/src/day12.rs @@ -13,11 +13,11 @@ impl Day for Day12 { let second = z[1]; { - let first_cave = caves.entry(first.to_string()).or_insert(Cave::new(first.into())); + let first_cave = caves.entry(first.to_string()).or_insert_with(|| Cave::new(first.into())); first_cave.add_connection(second); } { - let second_cave = caves.entry(second.to_string()).or_insert(Cave::new(second.into())); + let second_cave = caves.entry(second.to_string()).or_insert_with(|| Cave::new(second.into())); second_cave.add_connection(first); } } @@ -35,6 +35,7 @@ impl Day for Day12 { Ok(format!("{}", self.search("start", &m, false))) } } + #[derive(Ord, PartialOrd, Eq, PartialEq, Copy, Clone)] enum CaveType { Large, @@ -55,7 +56,7 @@ impl Cave { } fn new(cave_name: String) -> Self { - let cave_type = if cave_name.chars().nth(0).unwrap().is_uppercase() { + let cave_type = if cave_name.chars().next().unwrap().is_uppercase() { CaveType::Large } else { CaveType::Small @@ -70,10 +71,8 @@ impl Cave { impl Day12 { fn search(&self, cur: &str, had: &HashMap, part1: bool) -> i32 { let mut had = had.clone(); - if had.values().any(|&i| i > 1) || part1 { - if had.contains_key(cur) { - return 0; - } + if (had.values().any(|&i| i > 1) || part1) && had.contains_key(cur) { + return 0; } if cur == "start" && had.contains_key("start") { return 0; @@ -86,7 +85,7 @@ impl Day12 { let e = had.entry(cur.into()).or_insert(0); *e += 1; } - return n.connections.iter().map(|c| self.search(c, &mut had, part1)).sum::(); + return n.connections.iter().map(|c| self.search(c, &had, part1)).sum::(); } } diff --git a/src/day13.rs b/src/day13.rs index 02ed8dc..bad5b57 100644 --- a/src/day13.rs +++ b/src/day13.rs @@ -17,7 +17,7 @@ impl FromStr for Fold { type Err = (); fn from_str(s: &str) -> Result { - let r = s.rsplit(' ').nth(0).ok_or_else(|| ())?; + let r = s.rsplit(' ').next().ok_or(())?; let z = r.split('=').collect::>(); match z[0] { "x" => Ok(Fold::X(z[1].parse().map_err(|_| ())?)), @@ -31,7 +31,7 @@ impl FromStr for Fold { impl Day for Day13 { fn init(content: String) -> anyhow::Result { let l = content.lines(); - let points = l.clone().take_while(|&x| x != "").map(|st| st.split(',') + let points = l.clone().take_while(|&x| !x.is_empty()).map(|st| st.split(',') .map(str::parse).flatten().collect::>()).map(|v| (v[0], v[1])).collect::>(); Ok(Self { diff --git a/src/day14.rs b/src/day14.rs new file mode 100644 index 0000000..62b8308 --- /dev/null +++ b/src/day14.rs @@ -0,0 +1,149 @@ +use std::collections::HashMap; +use crate::Day; + +type ReplacementMap = HashMap>; + +pub struct Day14 { + start: HashMap, + end: char, + replacements: ReplacementMap, +} + +impl Day for Day14 { + fn init(content: String) -> anyhow::Result { + let mut line_iter = content.lines().peekable(); + let input: Vec = line_iter.next().unwrap().chars().collect(); + let mut start = HashMap::new(); + for i in 0..input.len() - 1 { + let pair = format!("{}{}", input[i], input[i + 1]); + let count = start.entry(pair).or_insert(0); + *count += 1; + } + + line_iter.next(); + + let mut replacements = HashMap::new(); + for line in line_iter { + let cap = line.split(" -> ").collect::>(); + + let pair = cap[0].to_string(); + let output = cap[1].to_string().chars().next().unwrap(); + replacements.insert( + pair.clone(), + vec![ + format!("{}{}", pair.chars().next().unwrap(), output), + format!("{}{}", output, pair.chars().nth(1).unwrap()), + ], + ); + } + + Ok(Self { + start, + replacements, + end: *input.last().unwrap(), + }) + } + + fn part1(&self) -> anyhow::Result { + Ok(format!("{}", self.iterate(10))) + } + + fn part2(&self) -> anyhow::Result { + Ok(format!("{}", self.iterate(40))) + } +} + +impl Day14 { + fn iterate(&self, amount: u64) -> u64 { + let mut s = self.start.clone(); + for _ in 0..amount { + s = do_pain(&s, &self.replacements); + } + + let mut counts: HashMap = HashMap::new(); + for (st, b) in s { + { + let e = counts.entry(st.chars().next().unwrap()).or_insert(0); + *e += b; + } + } + { + let e = counts.entry(self.end).or_insert(0); + *e += 1; + } + let mut min = u64::MAX; + let mut max = 0; + for &count in counts.values() { + min = min.min(count); + max = max.max(count); + } + max - min + } +} + +fn do_pain(input: &HashMap, map: &ReplacementMap) -> HashMap { + let mut output_map = HashMap::new(); + for (pair, &count) in input { + let new_pairs = map.get(pair).unwrap(); + + for new_pair in new_pairs { + let output_count = output_map.entry(new_pair.to_string()).or_insert(0); + *output_count += count; + } + } + + output_map +} + +#[cfg(test)] +mod tests { + use crate::day14::Day14; + use crate::day::Day; + + const INPUT: &str = r"NNCB + +CH -> B +HH -> N +CB -> H +NH -> C +HB -> C +HC -> B +HN -> C +NN -> C +BH -> H +NC -> B +NB -> B +BN -> B +BB -> N +BC -> B +CC -> N +CN -> C"; + + #[test] + fn part1_test() -> anyhow::Result<()> { + let d = Day14::init(INPUT.to_string())?; + assert_eq!("1588", d.part1()?); + Ok(()) + } + + #[test] + fn part2_test() -> anyhow::Result<()> { + let d = Day14::init(INPUT.to_string())?; + assert_eq!("2188189693529", d.part2()?); + Ok(()) + } + + #[test] + fn part1_real() -> anyhow::Result<()> { + let d = Day14::init(crate::load_input("14")?)?; + assert_eq!("2590", d.part1()?); + Ok(()) + } + + #[test] + fn part2_real() -> anyhow::Result<()> { + let d = Day14::init(crate::load_input("14")?)?; + assert_eq!("2875665202438", d.part2()?); + Ok(()) + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index bb3d30c..b766842 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,6 +16,7 @@ use crate::day10::Day10; use crate::day11::Day11; use crate::day12::Day12; use crate::day13::Day13; +use crate::day14::Day14; mod day; mod day01; @@ -31,6 +32,7 @@ mod day10; mod day11; mod day12; mod day13; +mod day14; fn load_input(day: &str) -> Result { read_to_string(format!("./input/day{}", day)).map_err(|x| x.into()) @@ -78,7 +80,8 @@ fn main() -> anyhow::Result<()> { Box::new(Day10::init(load_input("10")?)?), Box::new(Day11::init(load_input("11")?)?), Box::new(Day12::init(load_input("12")?)?), - Box::new(Day13::init(load_input("13")?)?),]; + Box::new(Day13::init(load_input("13")?)?), + Box::new(Day14::init(load_input("14")?)?),]; let _verbosity = matches.occurrences_of("v"); if matches.is_present("all") {