y2015d19 I should look at the input more

This commit is contained in:
Fabian Schmidt 2024-11-04 14:41:15 +01:00
parent 2f37793f02
commit fcf0a0866c
4 changed files with 177 additions and 0 deletions

View File

@ -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
CRnCaSiRnBSiRnFArTiBPTiTiBFArPBCaSiThSiRnTiBPBPMgArCaSiRnTiMgArCaSiThCaSiRnFArRnSiRnFArTiTiBFArCaCaSiRnSiThCaCaSiRnMgArFYSiRnFYCaFArSiThCaSiThPBPTiMgArCaPRnSiAlArPBCaCaSiRnFYSiThCaRnFArArCaCaSiRnPBSiRnFArMgYCaCaCaCaSiThCaCaSiAlArCaCaSiRnPBSiAlArBCaCaCaCaSiThCaPBSiThPBPBCaSiRnFYFArSiThCaSiRnFArBCaCaSiRnFYFArSiThCaPBSiThCaSiRnPMgArRnFArPTiBCaPRnFArCaCaCaCaSiRnCaCaSiRnFYFArFArBCaSiThFArThSiThSiRnTiRnPMgArFArCaSiThCaPBCaSiRnBFArCaCaPRnCaCaPMgArSiRnFYFArCaSiThRnPBPMgAr

20
y2015/src/bin/d19.rs Normal file
View File

@ -0,0 +1,20 @@
use std::fs;
use y2015::days::d19;
fn main() {
part1();
part2();
}
fn part1() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/19_input.txt")).unwrap();
println!("{}", d19::process_part1(&content));
}
fn part2() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/19_input.txt")).unwrap();
println!("{}", d19::process_part2(&content));
}

110
y2015/src/days/d19.rs Normal file
View File

@ -0,0 +1,110 @@
use std::collections::HashSet;
pub fn process_part1(input: &str) -> u32 {
let (replacements_str, molecule) = input.split_once("\n\n").unwrap();
let mut replacements = Vec::new();
replacements_str.lines().for_each(|line| {
let (from, to) = line.split_once(" => ").unwrap();
replacements.push((from, to));
});
let mut possible = HashSet::new();
for (from, to) in replacements {
molecule.match_indices(from).for_each(|(idx, _)| {
let mut new_possible = molecule.to_string();
new_possible.replace_range(idx..(idx + from.len()), to);
possible.insert(new_possible);
});
}
possible.len() as u32
}
// https://www.reddit.com/r/adventofcode/comments/3xflz8/comment/cy4etju/
// broken test
//First insight
//
//There are only two types of productions:
//
// e => XX and X => XX (X is not Rn, Y, or Ar)
//
// X => X Rn X Ar | X Rn X Y X Ar | X Rn X Y X Y X Ar
//
//Second insight
//
//You can think of Rn Y Ar as the characters ( , ):
//
//X => X(X) | X(X,X) | X(X,X,X)
//
//Whenever there are two adjacent "elements" in your "molecule", you apply the first production. This reduces your molecule length by 1 each time.
//
//And whenever you have T(T) T(T,T) or T(T,T,T) (T is a literal token such as "Mg", i.e. not a nonterminal like "TiTiCaCa"), you apply the second production. This reduces your molecule length by 3, 5, or 7.
//Third insight
//
//Repeatedly applying X => XX until you arrive at a single token takes count(tokens) - 1 steps:
//
//ABCDE => XCDE => XDE => XE => X
//count("ABCDE") = 5
//5 - 1 = 4 steps
//
//Applying X => X(X) is similar to X => XX, except you get the () for free. This can be expressed as count(tokens) - count("(" or ")") - 1.
//
//A(B(C(D(E)))) => A(B(C(X))) => A(B(X)) => A(X) => X
//count("A(B(C(D(E))))") = 13
//count("(((())))") = 8
//13 - 8 - 1 = 4 steps
//
//You can generalize to X => X(X,X) by noting that each , reduces the length by two (,X). The new formula is count(tokens) - count("(" or ")") - 2*count(",") - 1.
//
//A(B(C,D),E(F,G)) => A(B(C,D),X) => A(X,X) => X
//count("A(B(C,D),E(F,G))") = 16
//count("(()())") = 6
//count(",,,") = 3
//16 - 6 - 2*3 - 1 = 3 steps
//
//This final formula works for all of the production types (for X => XX, the (,) counts are zero by definition.)
pub fn process_part2(input: &str) -> u32 {
let (_replacements_str, molecule) = input.split_once("\n\n").unwrap();
// An element is always at least an uppercase character and possibly an additional lowercase
// character
let total_elements = molecule.chars().filter(|char| char.is_uppercase()).count();
let num_rn = molecule.matches("Rn").count();
let num_ar = molecule.matches("Ar").count();
let num_y = molecule.matches("Y").count();
(total_elements - (num_rn + num_ar) - 2 * num_y - 1) as u32
}
#[cfg(test)]
mod tests {
use super::*;
const INPUT1: &str = "H => HO
H => OH
O => HH
e => H
e => O
HOH";
const INPUT2: &str = "H => HO
H => OH
O => HH
e => H
e => O
HOHOHO";
#[test]
fn part1() {
let result = process_part1(INPUT1);
assert_eq!(result, 4);
let result = process_part1(INPUT2);
assert_eq!(result, 7);
}
#[test]
fn part2() {
let result = process_part2(INPUT1);
assert_eq!(result, 3);
let result = process_part2(INPUT2);
assert_eq!(result, 6);
}
}

View File

@ -16,3 +16,5 @@ pub mod d6;
pub mod d7;
pub mod d8;
pub mod d9;
pub mod d19;