]> aoc.elinar.fr Git - aoc_2023/commitdiff
Day19 - part 1
authoralex <null>
Tue, 19 Dec 2023 22:03:43 +0000 (23:03 +0100)
committeralex <null>
Wed, 20 Dec 2023 18:00:34 +0000 (19:00 +0100)
src/day19.rs [new file with mode: 0644]
src/main.rs

diff --git a/src/day19.rs b/src/day19.rs
new file mode 100644 (file)
index 0000000..30d5b57
--- /dev/null
@@ -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<dyn Error>> {
+    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<String, String>,
+    ratings: Vec<(u32, u32, u32, u32)>,
+}
+
+impl Puzzle {
+    pub fn new(input: &str) -> Self {
+        let mut workflows: HashMap<String, String> = 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<u32, Box<dyn Error>> {
+    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<u32, Box<dyn Error>> {
+    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());
+    }
+}
index 819dbc6bac97c937c84436b3b0d7369b2673b439..36bd08fc7b8a318ce070aa3a6c834cd71cf9b745 100644 (file)
@@ -18,6 +18,7 @@ pub mod day14;
 pub mod day15;
 pub mod day16;
 pub mod day18;
+pub mod day19;
 
 fn main() {
     let args: Vec<String> = env::args().collect();
@@ -51,6 +52,7 @@ fn run(day: &str, input_file: &str) -> Result<(), Box<dyn Error>> {
         "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(())