From 04592828776369cb58fcb65bda1962a7fc40e27f Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 19 Dec 2023 23:03:43 +0100 Subject: [PATCH] Day19 - part 1 --- src/day19.rs | 172 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 2 + 2 files changed, 174 insertions(+) create mode 100644 src/day19.rs diff --git a/src/day19.rs b/src/day19.rs new file mode 100644 index 0000000..30d5b57 --- /dev/null +++ b/src/day19.rs @@ -0,0 +1,172 @@ +use std::io::Read; +use std::error::Error; +use std::fs::File; + +use std::collections::HashMap; + +pub fn run(input_file: &str) -> Result<(), Box> { + let mut f = File::open(input_file)?; + let mut input = String::new(); + f.read_to_string(&mut input)?; + + let res = run_part1(&input)?; + println!("{res}"); + + let res = run_part2(&input)?; + println!("{res}"); + + Ok(()) +} + +#[derive(Debug)] +struct Puzzle { + workflows: HashMap, + ratings: Vec<(u32, u32, u32, u32)>, +} + +impl Puzzle { + pub fn new(input: &str) -> Self { + let mut workflows: HashMap = HashMap::new(); + + let (workflows_str, ratings_str) = input.split_once("\n\n").unwrap(); + workflows_str.lines() + .for_each(|l| { + let (key, rules) = l.split_once('{').unwrap(); + let rules = &rules[..rules.len() - 1]; + workflows.insert(key.to_string(), rules.to_string()); + }); + + // (x, m, a, s) + let ratings: Vec<(u32, u32, u32, u32)> = ratings_str.lines() + .filter_map(|l| { + match l.is_empty() { + true => None, + false => { + let values = &mut l[1..l.len() - 1].split(','); + let x: u32 = values.next().unwrap().split_once('=').unwrap().1.parse().unwrap(); + let m: u32 = values.next().unwrap().split_once('=').unwrap().1.parse().unwrap(); + let a: u32 = values.next().unwrap().split_once('=').unwrap().1.parse().unwrap(); + let s: u32 = values.next().unwrap().split_once('=').unwrap().1.parse().unwrap(); + Some((x, m, a, s)) + } + } + }) + .collect(); + + Self { + workflows, + ratings, + } + } + + pub fn travel_workflow(&self, (x, m, a, s): (u32, u32, u32, u32)) -> char { + //println!("(x,m,a,s): ({}, {}, {}, {})", x, m, a, s); + let mut key = "in"; + while self.workflows.contains_key(key) { + //println!("key: {}", key); + let rules = self.workflows.get(key).unwrap(); + //println!("rules: {}", rules); + for r in rules.split(',') { + //println!("r: {}", r); + if r.contains(':') { + let (cond, workflow) = r.split_once(':').unwrap(); + let cat: char = (&cond[0..1]).parse().unwrap(); + let op: char = (&cond[1..2]).parse().unwrap(); + let value: u32 = (&cond[2..]).parse().unwrap(); + //println!("cat: {}, {} , {}", cat, op, value); + + let test_rule = match cat { + 'x' => compare(x, op, value), + 'm' => compare(m, op, value), + 'a' => compare(a, op, value), + 's' => compare(s, op, value), + _ => unreachable!(), + }; + if test_rule { + key = workflow; + break; + } + } + else { + key = r; + } + } + } + + (&key[0..1]).parse().unwrap() + } + +} + +fn compare(x: u32, op: char, value: u32) -> bool { + match op { + '<' => x < value, + '>' => x > value, + '=' => x == value, + _ => unreachable!(), + } +} + + +fn run_part1(input: &str) -> Result> { + println!("Running day19 - part 1"); + + let puzzle = Puzzle::new(input); + + let res = puzzle.ratings.iter() + .map(|r| (puzzle.travel_workflow(*r), r)) + .filter_map(|(c, r)| { + match c { + 'R' => None, + 'A' => { + Some(r.0 + r.1 + r.2 + r.3) + }, + _ => unreachable!(), + } + }) + .sum(); + + Ok(res) +} + +fn run_part2(input: &str) -> Result> { + println!("Running day19 - part 2"); + let res = 0; + Ok(res) +} + +#[cfg(test)] +mod tests { + use super::*; + + static TEXT_INPUT: &str = "\ +px{a<2006:qkq,m>2090:A,rfg} +pv{a>1716:R,A} +lnx{m>1548:A,A} +rfg{s<537:gd,x>2440:R,A} +qs{s>3448:A,lnx} +qkq{x<1416:A,crn} +crn{x>2662:A,R} +in{s<1351:px,qqz} +qqz{s>2770:qs,m<1801:hdj,R} +gd{a>3333:R,R} +hdj{m>838:A,pv} + +{x=787,m=2655,a=1222,s=2876} +{x=1679,m=44,a=2067,s=496} +{x=2036,m=264,a=79,s=2244} +{x=2461,m=1339,a=466,s=291} +{x=2127,m=1623,a=2188,s=1013}"; + + #[test] + fn day19_part1() { + let res = run_part1(TEXT_INPUT); + assert_eq!(19114, res.unwrap()); + } + + #[test] + fn day19_part2() { + let res = run_part2(TEXT_INPUT); + assert_eq!(0, res.unwrap()); + } +} diff --git a/src/main.rs b/src/main.rs index 819dbc6..36bd08f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,6 +18,7 @@ pub mod day14; pub mod day15; pub mod day16; pub mod day18; +pub mod day19; fn main() { let args: Vec = env::args().collect(); @@ -51,6 +52,7 @@ fn run(day: &str, input_file: &str) -> Result<(), Box> { "day15" => day15::run(input_file)?, "day16" => day16::run(input_file)?, "day18" => day18::run(input_file)?, + "day19" => day19::run(input_file)?, _ => return Err(format!("unknown day \"{day}\"").into()), } Ok(()) -- 2.39.5