From 92fc7c8fcd165e8a60f6072a068ccddb0e85c1b1 Mon Sep 17 00:00:00 2001 From: Pierre Gagelin Date: Wed, 16 Nov 2022 22:22:11 +0100 Subject: [PATCH] Added solution to puzzle 2015/day19 --- 2015/day19/Cargo.toml | 8 +++ 2015/day19/day19.rs | 142 ++++++++++++++++++++++++++++++++++++++++++ 2015/day19/test01.txt | 5 ++ 2015/day19/test02.txt | 5 ++ 2015/day19/test03.txt | 7 +++ 2015/day19/test04.txt | 7 +++ 2015/day19/test05.txt | 45 +++++++++++++ README.md | 1 + 8 files changed, 220 insertions(+) create mode 100644 2015/day19/Cargo.toml create mode 100644 2015/day19/day19.rs create mode 100644 2015/day19/test01.txt create mode 100644 2015/day19/test02.txt create mode 100644 2015/day19/test03.txt create mode 100644 2015/day19/test04.txt create mode 100644 2015/day19/test05.txt diff --git a/2015/day19/Cargo.toml b/2015/day19/Cargo.toml new file mode 100644 index 0000000..05e2693 --- /dev/null +++ b/2015/day19/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "day19" +version = "0.1.0" +edition = "2021" + +[[bin]] +name = "day19" +path = "day19.rs" diff --git a/2015/day19/day19.rs b/2015/day19/day19.rs new file mode 100644 index 0000000..df8f271 --- /dev/null +++ b/2015/day19/day19.rs @@ -0,0 +1,142 @@ +//! [Day 19: Medicine for Rudolph](https://adventofcode.com/2015/day/19) + +use std::collections::HashSet; +use std::env; +use std::fs; + +struct Puzzle { + medicine_molecule: String, + replacements: Vec<(String, String)>, +} + +impl Puzzle { + fn new() -> Puzzle { + Puzzle { + medicine_molecule: String::new(), + replacements: Vec::new(), + } + } + + fn configure(&mut self, filename: &str) { + let mut data: Vec = fs::read_to_string(filename) + .expect("Failed to read input file") + .lines() + .map(ToString::to_string) + .collect(); + + self.medicine_molecule = data.pop().unwrap(); + + // Remove empty delimiter + data.pop(); + + for line in data { + // Get the replacement rule + let mut replacement: Vec<&str> = line.split(" => ").collect(); + let to = replacement.pop().unwrap().to_string(); + let from = replacement.pop().unwrap().to_string(); + self.replacements.push((from, to)); + } + } + + fn part1(&mut self) -> usize { + let mut molecules = HashSet::new(); + + for (from, to) in &self.replacements { + // Split the molecule on each atom + let sub_molecules: Vec = self + .medicine_molecule + .split_inclusive(from) + .map(ToString::to_string) + .collect(); + + // Apply the replacement rule for each atom found + for (i, sub_mol) in sub_molecules.iter().enumerate() { + let mut generated_molecule = sub_molecules.clone(); + let sub_mol = sub_mol.replace(from, to); + generated_molecule[i] = sub_mol; + molecules.insert(generated_molecule.concat()); + } + } + molecules.remove(&self.medicine_molecule); + + molecules.len() + } + + /// This resolution works but it's not truly what's asked by the puzzle. We don't know if this + /// method yields the lowest count of iterations required to produce the molecule. Finding the + /// lowest count of iterations is a way harder puzzle and was probably not meant by the author + /// of the puzzle. The puzzle input is probably designed in order for only one answer to rise. + fn part2(&mut self) -> usize { + let mut iterations = 0_usize; + + // Reduce the medicine molecule to the electron is equivalent to create the medicine molecule from the electron + while self.medicine_molecule != "e" { + for (from, to) in &self.replacements { + // Reverse apply the replacement only once + if self.medicine_molecule.find(to) != None { + self.medicine_molecule = self.medicine_molecule.replacen(to, from, 1); + break; + } + } + iterations += 1; + } + + iterations + } +} + +/// Test from the puzzle description +#[test] +fn test1() { + let mut puzzle = Puzzle::new(); + puzzle.configure("test01.txt"); + assert_eq!(puzzle.part1(), 4); +} + +/// Test from the puzzle description +#[test] +fn test2() { + let mut puzzle = Puzzle::new(); + puzzle.configure("test02.txt"); + assert_eq!(puzzle.part1(), 7); +} + +/// Test from the puzzle description +#[ignore = "Heuristic made to solve the problem does not work here"] +#[test] +fn test3() { + let mut puzzle = Puzzle::new(); + puzzle.configure("test03.txt"); + assert_eq!(puzzle.part2(), 3); +} + +/// Test from the puzzle description +#[ignore = "Heuristic made to solve the problem does not work here"] +#[test] +fn test4() { + let mut puzzle = Puzzle::new(); + puzzle.configure("test04.txt"); + assert_eq!(puzzle.part2(), 6); +} + +/// Test from a player's input +#[test] +fn test5() { + let mut puzzle = Puzzle::new(); + puzzle.configure("test05.txt"); + assert_eq!(puzzle.part1(), 518); + assert_eq!(puzzle.part2(), 200); +} + +fn main() { + let mut puzzle = Puzzle::new(); + + let args: Vec = env::args().collect(); + puzzle.configure(args.get(1).expect("No input file")); + + let result = puzzle.part1(); + println!("{}", result); + + let result = puzzle.part2(); + println!("{}", result); +} diff --git a/2015/day19/test01.txt b/2015/day19/test01.txt new file mode 100644 index 0000000..1798c27 --- /dev/null +++ b/2015/day19/test01.txt @@ -0,0 +1,5 @@ +H => HO +H => OH +O => HH + +HOH diff --git a/2015/day19/test02.txt b/2015/day19/test02.txt new file mode 100644 index 0000000..fdc20b0 --- /dev/null +++ b/2015/day19/test02.txt @@ -0,0 +1,5 @@ +H => HO +H => OH +O => HH + +HOHOHO diff --git a/2015/day19/test03.txt b/2015/day19/test03.txt new file mode 100644 index 0000000..f483a37 --- /dev/null +++ b/2015/day19/test03.txt @@ -0,0 +1,7 @@ +e => H +e => O +H => HO +H => OH +O => HH + +HOH diff --git a/2015/day19/test04.txt b/2015/day19/test04.txt new file mode 100644 index 0000000..70905c4 --- /dev/null +++ b/2015/day19/test04.txt @@ -0,0 +1,7 @@ +e => H +e => O +H => HO +H => OH +O => HH + +HOHOHO diff --git a/2015/day19/test05.txt b/2015/day19/test05.txt new file mode 100644 index 0000000..b0515c0 --- /dev/null +++ b/2015/day19/test05.txt @@ -0,0 +1,45 @@ +Al => ThF +Al => ThRnFAr +B => BCa +B => TiB +B => TiRnFAr +Ca => CaCa +Ca => PB +Ca => PRnFAr +Ca => SiRnFYFAr +Ca => SiRnMgAr +Ca => SiTh +F => CaF +F => PMg +F => SiAl +H => CRnAlAr +H => CRnFYFYFAr +H => CRnFYMgAr +H => CRnMgYFAr +H => HCa +H => NRnFYFAr +H => NRnMgAr +H => NTh +H => OB +H => ORnFAr +Mg => BF +Mg => TiMg +N => CRnFAr +N => HSi +O => CRnFYFAr +O => CRnMgAr +O => HP +O => NRnFAr +O => OTi +P => CaP +P => PTi +P => SiRnFAr +Si => CaSi +Th => ThCa +Ti => BP +Ti => TiTi +e => HF +e => NAl +e => OMg + +CRnSiRnCaPTiMgYCaPTiRnFArSiThFArCaSiThSiThPBCaCaSiRnSiRnTiTiMgArPBCaPMgYPTiRnFArFArCaSiRnBPMgArPRnCaPTiRnFArCaSiThCaCaFArPBCaCaPTiTiRnFArCaSiRnSiAlYSiThRnFArArCaSiRnBFArCaCaSiRnSiThCaCaCaFYCaPTiBCaSiThCaSiThPMgArSiRnCaPBFYCaCaFArCaCaCaCaSiThCaSiRnPRnFArPBSiThPRnFArSiRnMgArCaFYFArCaSiRnSiAlArTiTiTiTiTiTiTiRnPMgArPTiTiTiBSiRnSiAlArTiTiRnPMgArCaFYBPBPTiRnSiRnMgArSiThCaFArCaSiThFArPRnFArCaSiRnTiBSiThSiRnSiAlYCaFArPRnFArSiThCaFArCaCaSiThCaCaCaSiRnPRnCaFArFYPMgArCaPBCaPBSiRnFYPBCaFArCaSiAl diff --git a/README.md b/README.md index 123055e..09a7d4a 100644 --- a/README.md +++ b/README.md @@ -88,5 +88,6 @@ Puzzle [Day 16: Aunt Sue](https://adventofcode.com/2015/day/16) | ⭐⭐ | Rust Python [Day 17: No Such Thing as Too Much](https://adventofcode.com/2015/day/17) | ⭐⭐ | Rust [Day 18: Like a GIF For Your Yard](https://adventofcode.com/2015/day/18) | ⭐⭐ | Rust +[Day 19: Medicine for Rudolph](https://adventofcode.com/2015/day/19) | ⭐⭐ | Rust [Day 20: Infinite Elves and Infinite Houses](https://adventofcode.com/2015/day/20) | ⭐⭐ | Rust [Day 25: Let It Snow](https://adventofcode.com/2015/day/25) | ⭐ | Rust