Skip to content

Commit

Permalink
Year 2015: Day 19
Browse files Browse the repository at this point in the history
  • Loading branch information
joshleaves committed Mar 2, 2024
1 parent e8b38ac commit 46c8426
Show file tree
Hide file tree
Showing 9 changed files with 228 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ Of note:
- The changelog 2015.5.2 has been rewritten from each commit content.
- This file may be amended entirely in the future to adhere to the [GNU Changelog style](https://www.gnu.org/prep/standards/html_node/Style-of-Change-Logs.html#Style-of-Change-Logs)

## [2015.19.1]
### Added
- Solved [exercice for 2015, day 19](src/year_2015/day_19.rs).

## [2015.18.1]
### Added
- Solved [exercice for 2015, day 18](src/year_2015/day_18.rs).
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "advent-rs"
version = "2015.18.1"
version = "2015.19.1"
edition = "2021"
authors = ["Arnaud 'red' Rouyer"]
readme = "README.md"
Expand Down
25 changes: 25 additions & 0 deletions NOTES_2015.md
Original file line number Diff line number Diff line change
Expand Up @@ -533,3 +533,28 @@ year_2015::day_18/year_2015::day_18_v2
That was fun.

My [distinguished competitor](https://docs.rs/advent-of-code/2022.0.66/src/advent_of_code/year2015/day18.rs.html) used a single-dimensional vector approach, which may have a better performance, but quite frankly, I prefer having representation closer to "physical" reality. But it's just me, don't listen to me too much.

## Day 19: Medicine for Rudolph

<details>
<summary>📊Tests and benchmarks</summary>

```
test year_2015::day_19::tests::works_with_samples_v1 ... ok
test year_2015::day_19::tests::works_with_samples_v2 ... ok
test year_2015_day_19 ... ok
year_2015::day_19/year_2015::day_19_v1
time: [565.05 µs 565.71 µs 566.40 µs]
year_2015::day_19/year_2015::day_19_v2
time: [6.0105 µs 6.0169 µs 6.0237 µs]
```
</details>

<details>
<summary>Ruby version comments</summary>

> Part one is nothing to write home about. However, part two... First idea was the good ol' bruteforce approach, but when searching if there was an algorithm I didn't know, I stumbled upon a [very interesting Reddit comment](https://www.reddit.com/r/adventofcode/comments/3xflz8/day_19_solutions/cy4h7ji/)...
</details>
Okay, that was less painful than I remembered it, and my Rust code is actually clearer than my Ruby code.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ As I said, [Consistency is hard](https://github.com/joshleaves/advent-rb), and I
I'm also adding notes that may be useful if you're discovering Rust (like I am).

Notes for solving:
* [2015, up to day 16](NOTES_2015.md)
* [2015, up to day 19](NOTES_2015.md)

# Regarding style rules
I'm gonna use a mix of what `cargo fmt` does, with some stuff that feels more natural to me.
Expand Down
11 changes: 11 additions & 0 deletions benches/advent-bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use advent_rs::year_2015::day_15;
use advent_rs::year_2015::day_16;
use advent_rs::year_2015::day_17;
use advent_rs::year_2015::day_18;
use advent_rs::year_2015::day_19;
use criterion::{black_box, criterion_group, criterion_main, Criterion};

pub fn year_2015_benchmark(c: &mut Criterion) {
Expand Down Expand Up @@ -200,6 +201,16 @@ pub fn year_2015_benchmark(c: &mut Criterion) {
b.iter(|| day_18::day_18_v2(black_box(input_year_2015_day_18)))
});
g2015_day_18.finish();

let mut g2015_day_19 = c.benchmark_group("year_2015::day_19");
let input_year_2015_day_19 = include_str!("../inputs/year_2015_day_19_input");
g2015_day_19.bench_function("year_2015::day_19_v1", |b| {
b.iter(|| day_19::day_19_v1(black_box(input_year_2015_day_19)))
});
g2015_day_19.bench_function("year_2015::day_19_v2", |b| {
b.iter(|| day_19::day_19_v2(black_box(input_year_2015_day_19)))
});
g2015_day_19.finish();
}

criterion_group!(benches, year_2015_benchmark);
Expand Down
45 changes: 45 additions & 0 deletions inputs/year_2015_day_19_input
Original file line number Diff line number Diff line change
@@ -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

ORnPBPMgArCaCaCaSiThCaCaSiThCaCaPBSiRnFArRnFArCaCaSiThCaCaSiThCaCaCaCaCaCaSiRnFYFArSiRnMgArCaSiRnPTiTiBFYPBFArSiRnCaSiRnTiRnFArSiAlArPTiBPTiRnCaSiAlArCaPTiTiBPMgYFArPTiRnFArSiRnCaCaFArRnCaFArCaSiRnSiRnMgArFYCaSiRnMgArCaCaSiThPRnFArPBCaSiRnMgArCaCaSiThCaSiRnTiMgArFArSiThSiThCaCaSiRnMgArCaCaSiRnFArTiBPTiRnCaSiAlArCaPTiRnFArPBPBCaCaSiThCaPBSiThPRnFArSiThCaSiThCaSiThCaPTiBSiRnFYFArCaCaPRnFArPBCaCaPBSiRnTiRnFArCaPRnFArSiRnCaCaCaSiThCaRnCaFArYCaSiRnFArBCaCaCaSiThFArPBFArCaSiRnFArRnCaCaCaFArSiRnFArTiRnPMgArF
2 changes: 2 additions & 0 deletions src/year_2015.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub mod day_15;
pub mod day_16;
pub mod day_17;
pub mod day_18;
pub mod day_19;

/// Returns the solution for a specified exercise and input.
///
Expand Down Expand Up @@ -63,6 +64,7 @@ pub fn solve(day: u8, part: u8, input: impl Into<String>) -> Option<String> {
16 => return Some(format!("{}", day_16::day_16(part, input))),
17 => return Some(format!("{}", day_17::day_17(part, input))),
18 => return Some(format!("{}", day_18::day_18(part, input))),
19 => return Some(format!("{}", day_19::day_19(part, input))),
_ => return None,
}
}
131 changes: 131 additions & 0 deletions src/year_2015/day_19.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
use std::collections::{HashMap, HashSet};

fn parse_molecules(input: &str) -> (String, String) {
let parts: Vec<_> = input.split(" => ").collect();
(parts[0].to_string(), parts[1].to_string())
}

fn parse_input(input: &str) -> (HashMap<String, Vec<String>>, String) {
let mut molecules: HashMap<String, Vec<String>> = HashMap::new();
let mut starter: String = String::new();
let mut reached_target = false;
for line in input.lines() {
if line.is_empty() {
reached_target = true;
continue;
}
if reached_target {
starter.push_str(line);
continue;
}
let (from, to) = parse_molecules(line);
molecules.entry(from).or_insert_with(Vec::new).push(to);
}

(molecules, starter)
}

fn do_permutations(starter: &str, input: &str, replacements: &Vec<String>) -> HashSet<String> {
// re_input = /(#{input})/
// parts = starter.scan(re_input).length
// replacements.each do |replacement|
// 0.upto(parts - 1) do |idx|
// new_str = starter.gsub(re_input).each_with_index do |_part, i|
// idx == i ? replacement : input
// end
// @permutations.push(new_str)
// end
// end
let mut permutations: HashSet<String> = HashSet::new();
for (idx, _) in starter.match_indices(input) {
for replacement in replacements.iter() {
let new_permutation = format!(
"{}{}{}",
&starter[..idx],
replacement,
&starter[idx + input.len()..]
);
permutations.insert(new_permutation);
}
}

permutations
}

fn calculate_permutations(molecules: &HashMap<String, Vec<String>>, starter: &str) -> usize {
// @permutations ||= begin
// @permutations = []
// @molecules.each do |input, replacements|
// do_permutations(input, replacements)
// end
// @permutations.sort.uniq
// end
let mut permutations: HashSet<String> = HashSet::new();
for (molecule, replacements) in molecules {
let new_permutations = do_permutations(&starter, &molecule, &replacements);
permutations.extend(new_permutations);
}
permutations.len()
}

pub fn day_19_v1(input: impl Into<String>) -> usize {
let (molecules, starter) = parse_input(&input.into());

calculate_permutations(&molecules, &starter)
}

pub fn day_19_v2(input: impl Into<String>) -> usize {
let (_molecules, starter) = parse_input(&input.into());

let mut count_az = 0;
let mut count_rn = 0;
let mut count_ar = 0;
let mut count_y = 0;
let letters: Vec<_> = starter.chars().collect();
for (idx, chr) in letters.iter().enumerate() {
match chr {
'A' => {
count_az += 1;
if letters[idx + 1] == 'r' {
count_ar += 1;
}
}
'R' => {
count_az += 1;
if letters[idx + 1] == 'n' {
count_rn += 1;
}
}
'Y' => {
count_az += 1;
count_y += 1;
}
_ => {
if *chr >= 'A' && *chr <= 'Z' {
count_az += 1;
}
}
}
}

count_az - count_rn - count_ar - (2 * count_y) - 1
}

solvable!(day_19, day_19_v1, day_19_v2, usize);

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn works_with_samples_v1() {
let sample_one = "H => HO\nH => OH\nO => HH\n\n\nHOH";
assert_eq!(day_19_v1(sample_one), 4);
}

#[test]
fn works_with_samples_v2() {
let sample_two = "e => H\ne => O\nH => HO\nH => OH\nO => HH\n\nHOHOHO;";
assert_eq!(day_19_v2(sample_two), 5);
}
}
8 changes: 8 additions & 0 deletions tests/year_2015_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use advent_rs::year_2015::day_15;
use advent_rs::year_2015::day_16;
use advent_rs::year_2015::day_17;
use advent_rs::year_2015::day_18;
use advent_rs::year_2015::day_19;

#[test]
fn year_2015_day_01() {
Expand Down Expand Up @@ -141,3 +142,10 @@ fn year_2015_day_18() {
assert_eq!(day_18::day_18_v1(input), 821);
assert_eq!(day_18::day_18_v2(input), 886);
}

#[test]
fn year_2015_day_19() {
let input = include_str!("../inputs/year_2015_day_19_input");
assert_eq!(day_19::day_19_v1(input), 576);
assert_eq!(day_19::day_19_v2(input), 207);
}

0 comments on commit 46c8426

Please sign in to comment.