commit 91ac0a0688eb2dce6d2b2a176d26805f2f153067 Author: Leon Grünewald Date: Thu Dec 12 02:48:10 2024 +0100 Finish challenge 5 diff --git a/5/.gitignore b/5/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/5/.gitignore @@ -0,0 +1 @@ +/target diff --git a/5/Cargo.lock b/5/Cargo.lock new file mode 100644 index 0000000..c3ab706 --- /dev/null +++ b/5/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" + +[[package]] +name = "aoc24-5" +version = "0.1.0" +dependencies = [ + "anyhow", +] diff --git a/5/Cargo.toml b/5/Cargo.toml new file mode 100644 index 0000000..4ae52c8 --- /dev/null +++ b/5/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "aoc24-5" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1.0" diff --git a/5/src/main.rs b/5/src/main.rs new file mode 100644 index 0000000..254a9e3 --- /dev/null +++ b/5/src/main.rs @@ -0,0 +1,84 @@ +use std::fs::OpenOptions; +use std::io::Read; +use anyhow::bail; + +fn get_data() -> anyhow::Result { + let args = std::env::args(); + + // First argument is the executable, second argument is the path to our input. + if args.len() < 2 { bail!("Not enough arguments") } + + let mut data = String::new(); + { + let mut file = OpenOptions::new().read(true).open(args.last().expect("No file path"))?; + file.read_to_string(&mut data)?; + } + Ok(data) +} + +fn parse_rules_and_updates(data: &String) -> (Vec<(&str, &str)>, Vec>){ + let (rules, mut rest): (Vec<&str>, _) = data.lines() + .partition(|line| line.contains("|")); + + let rules: Vec<(&str, &str)> = rules.into_iter() + .map(|rule| rule.split_once("|").expect("Could not split")) + .collect(); + + rest.drain(0..1); + + let updates: Vec> = rest.into_iter() + .map(|page| page.split(",").collect()) + .collect(); + + (rules, updates) +} + +fn check_rule_compliance(update: &Vec<&str>, rule: &(&str, &str)) -> Option<(usize, usize)> { + let before_index_opt = update.iter().position(|elem| {*elem == rule.0}); + let after_index_opt = update.iter().position(|elem| {*elem == rule.1}); + + match (before_index_opt, after_index_opt) { + (Some(before_index), Some(after_index)) => { + if before_index > after_index { + return Some((before_index, after_index)); + } + } + _ => { + // println!("Skipping rule {rule:?}"); + } + } + None +} + +fn sum_middle_page_nums(updates: Vec>) -> i64 { + updates.iter() + .map(|update| update[update.len()/2]) + .map(|middle| middle.parse::().unwrap()) + .sum() +} + +fn main() -> anyhow::Result<()> { + let data = get_data()?; + let (rules, updates) = parse_rules_and_updates(&data); + let mut correct_updates = Vec::new(); + + 'update: for update in updates { + for rule in &rules { + if let Some(_) = check_rule_compliance(&update, rule) { + /*println!( + "Rule issue: {:?} ({before_index:?}) {:?} ({after_index:?})", + update[before_index], + update[after_index] + ); + println!("Elements: {update:?}");*/ + continue 'update; + } + } + correct_updates.push(update); + } + + println!("{}", sum_middle_page_nums(correct_updates)); + Ok(()) +} + +