Guest User

Untitled

a guest
Dec 19th, 2023
117
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 9.99 KB | None | 0 0
  1. use std::collections::HashMap;
  2. use std::hash::BuildHasherDefault;
  3. use std::time::Instant;
  4. use regex::Regex;
  5. use rustc_hash::{FxHasher, FxHashMap};
  6.  
  7.  
  8. #[derive(Eq, PartialEq, Debug, Copy, Clone)]
  9. enum Operator {
  10.     GT,
  11.     LT,
  12.     Immediate,
  13. }
  14.  
  15. #[derive(Eq, PartialEq, Debug, Copy, Clone)]
  16. struct Rule<'a> {
  17.    category: Option<&'a str>,
  18.     operator: Operator,
  19.     value: Option<i32>,
  20.     target: &'a str,
  21. }
  22.  
  23. impl<'a> Rule<'a> {
  24.    fn opposite(&self) -> Rule<'a> {
  25.         match self.operator {
  26.             Operator::GT => Self {
  27.                 category: self.category,
  28.                 operator: Operator::LT,
  29.                 value: Some(self.value.unwrap() + 1),
  30.                 target: self.target
  31.             },
  32.             Operator::LT => Self {
  33.                 category: self.category,
  34.                 operator: Operator::GT,
  35.                 value: Some(self.value.unwrap() - 1),
  36.                 target: self.target
  37.             },
  38.             Operator::Immediate => panic!("Can't get opposite of immediate rule")
  39.         }
  40.     }
  41.  
  42.     fn new(input: &'a str) -> Self {
  43.        let rule_re = Regex::new(r"^(?<category>\w)(?<operator>[<|>])(?<value>\d+):(?<target>\w+)$").unwrap();
  44.        if let Some(captures) = rule_re.captures(input) {
  45.            let category = Some(captures.name("category").unwrap().as_str());
  46.            let operator = match captures.name("operator").unwrap().as_str() {
  47.                ">" => Operator::GT,
  48.                "<" => Operator::LT,
  49.                other => panic!("Unknown operator: {}", other)
  50.            };
  51.            let value = Some(captures.name("value").unwrap().as_str().parse().unwrap());
  52.            let target = captures.name("target").unwrap().as_str();
  53.  
  54.            return Self {
  55.                category,
  56.                operator,
  57.                value,
  58.                target,
  59.            };
  60.        }
  61.  
  62.        Self {
  63.            category: None,
  64.            value: None,
  65.            operator: Operator::Immediate,
  66.            target: input,
  67.        }
  68.    }
  69. }
  70.  
  71. #[derive(Debug)]
  72. struct Workflow<'a> {
  73.     name: &'a str,
  74.    rules: Vec<Rule<'a>>,
  75. }
  76.  
  77. impl<'a> Workflow<'a> {
  78.     fn new(input: &'a str) -> Self {
  79.        let re = Regex::new(r"^(?<name>\w+)\{(?<rules>\S+)}$").unwrap();
  80.        let captures = re.captures(input).unwrap();
  81.  
  82.        let name = captures.name("name").unwrap().as_str();
  83.        let rules = captures.name("rules").unwrap().as_str()
  84.            .split(",")
  85.            .map(Rule::new)
  86.            .collect::<Vec<_>>();
  87.  
  88.        Self {
  89.            name,
  90.            rules,
  91.        }
  92.    }
  93. }
  94.  
  95. type WorkflowMap<'a> = HashMap<&'a str, Workflow<'a>, BuildHasherDefault<FxHasher>>;
  96.  
  97. fn parse(input: &str) -> WorkflowMap {
  98.     let [input_workflows, _input_parts] = input.split("\n\n").collect::<Vec<_>>().try_into().unwrap();
  99.  
  100.     let workflow_map = FxHashMap::from_iter(input_workflows.lines()
  101.         .map(Workflow::new)
  102.         .map(|w| (w.name, w))
  103.     );
  104.  
  105.     workflow_map
  106. }
  107.  
  108. #[derive(Copy, Clone, Debug)]
  109. struct Constraint<'a> {
  110.    category: &'a str,
  111.     operator: Operator,
  112.     value: i32,
  113. }
  114.  
  115. impl<'a> From<Rule<'a>> for Constraint<'a> {
  116.    fn from(rule: Rule<'a>) -> Self {
  117.         Constraint {
  118.             category: rule.category.unwrap(),
  119.             operator: rule.operator,
  120.             value: rule.value.unwrap(),
  121.         }
  122.     }
  123. }
  124.  
  125.  
  126. fn get_constraints(workflows: WorkflowMap) -> Vec<Vec<Constraint>> {
  127.     let constraints = Vec::new();
  128.     let initial_workflow = "in";
  129.     let initial_rule = 0;
  130.     return _get_constraints(constraints, &workflows, initial_workflow, initial_rule)
  131.         .iter()
  132.         .filter_map(|x| x.clone())
  133.         .collect()
  134. }
  135.  
  136. fn _get_constraints<'a>(constraints: Vec::<Constraint<'a>>, workflows: &WorkflowMap<'a>, cur_workflow: &str, cur_rule: usize) -> Vec<Option<Vec<Constraint<'a>>>> {
  137.  
  138.     match cur_workflow {
  139.         "A" => return vec![Some(constraints.clone())],
  140.         "R" => return vec![None],
  141.         _ => {}
  142.     };
  143.  
  144.     let workflow = workflows.get(cur_workflow).unwrap();
  145.     let rule = workflow.rules[cur_rule];
  146.  
  147.     return match (rule.operator, rule.category, rule.value, rule.target) {
  148.         (Operator::Immediate, _, _, "A") => vec![Some(constraints.clone())],
  149.         (Operator::Immediate, _, _, "R") => vec![None],
  150.         (Operator::Immediate, _, _, target) => _get_constraints(constraints.clone(), workflows, target, 0),
  151.  
  152.         (Operator::GT | Operator::LT, _, _, target) => {
  153.  
  154.             let mut new_constraints_left = constraints.clone();
  155.             new_constraints_left.push(rule.into());
  156.             let mut new_constraints_right = constraints.clone();
  157.             new_constraints_right.push(rule.opposite().into());
  158.  
  159.             let mut tmp = _get_constraints(new_constraints_left, workflows, target, 0);
  160.             tmp.append(&mut _get_constraints(new_constraints_right, workflows, cur_workflow, cur_rule + 1));
  161.             return tmp;
  162.  
  163.         }
  164.     };
  165. }
  166.  
  167. fn find_possibilities(constraint_sets: Vec<Vec<Constraint>>) -> u64 {
  168.     let mut total: u64 = 0;
  169.  
  170.     for constraints in constraint_sets {
  171.  
  172.         let mut x_min = 0;
  173.         let mut m_min = 0;
  174.         let mut a_min = 0;
  175.         let mut s_min = 0;
  176.         let mut x_max = 4000;
  177.         let mut m_max = 4000;
  178.         let mut a_max = 4000;
  179.         let mut s_max = 4000;
  180.  
  181.         for Constraint {category, operator, value} in constraints {
  182.             match operator {
  183.                 Operator::GT => {
  184.                     match category {
  185.                         "x" => x_min = value as u64,
  186.                         "m" => m_min = value as u64,
  187.                         "a" => a_min = value as u64,
  188.                         "s" => s_min = value as u64,
  189.                         _ => panic!()
  190.                     }
  191.                 }
  192.                 Operator::LT => {
  193.                     match category {
  194.                         "x" => x_max = value as u64 - 1,
  195.                         "m" => m_max = value as u64 - 1,
  196.                         "a" => a_max = value as u64 - 1,
  197.                         "s" => s_max = value as u64 - 1,
  198.                         _ => panic!()
  199.                     }
  200.                 }
  201.                 Operator::Immediate => panic!()
  202.             }
  203.         }
  204.  
  205.         total += (x_max - x_min) * (m_max - m_min) * (a_max - a_min) * (s_max - s_min)
  206.  
  207.     }
  208.     total
  209. }
  210.  
  211. fn main() {
  212.  
  213.     let parse_start = Instant::now();
  214.     let input = include_str!("../input.txt");
  215.     let workflows = parse(input);
  216.     let parse_time = parse_start.elapsed();
  217.     println!("Parsing took: {:?}", parse_time);
  218.  
  219.     let constraints_start = Instant::now();
  220.     let constraints = get_constraints(workflows);
  221.     let constraints_time = constraints_start.elapsed();
  222.     println!("Finding constraints took: {:?}", constraints_time);
  223.  
  224.     let solving_start = Instant::now();
  225.     let result = find_possibilities(constraints);
  226.     let solving_time = solving_start.elapsed();
  227.     println!("Solving took: {:?}", solving_time);
  228.  
  229.     println!("Result: {}", result);
  230. }
  231.  
  232. #[cfg(test)]
  233. mod test {
  234.     use super::*;
  235.  
  236.     static TEST_INPUT: &str = "px{a<2006:qkq,m>2090:A,rfg}
  237. pv{a>1716:R,A}
  238. lnx{m>1548:A,A}
  239. rfg{s<537:gd,x>2440:R,A}
  240. qs{s>3448:A,lnx}
  241. qkq{x<1416:A,crn}
  242. crn{x>2662:A,R}
  243. in{s<1351:px,qqz}
  244. qqz{s>2770:qs,m<1801:hdj,R}
  245. gd{a>3333:R,R}
  246. hdj{m>838:A,pv}
  247.  
  248. {x=787,m=2655,a=1222,s=2876}
  249. {x=1679,m=44,a=2067,s=496}
  250. {x=2036,m=264,a=79,s=2244}
  251. {x=2461,m=1339,a=466,s=291}
  252. {x=2127,m=1623,a=2188,s=1013}";
  253.  
  254.     #[test]
  255.     fn test_input_1() {
  256.         let input = TEST_INPUT;
  257.         let workflows = parse(input);
  258.         let constraints = get_constraints(workflows);
  259.         let result = find_possibilities(constraints);
  260.         assert_eq!(result, 167409079868000);
  261.     }
  262.  
  263.     #[test]
  264.     fn test_input_2() {
  265.         let input = "in{x>3998:pb,R}
  266. pb{m>3998:pc,R}
  267. pc{a>3998:pd,R}
  268. pd{s>3998:A,R}
  269.  
  270. ";
  271.         let workflows = parse(input);
  272.         let constraints = get_constraints(workflows);
  273.         let result = find_possibilities(constraints);
  274.         assert_eq!(result, 16);
  275.     }
  276.  
  277.     #[test]
  278.     fn test_input_3() {
  279.         let input = "in{x>3999:pb,x<2:pe,R}
  280. pb{m>3999:pc,R}
  281. pc{a>3999:pd,R}
  282. pd{s>3999:A,R}
  283. pe{m<2:pf,R}
  284. pf{a<2:pg,R}
  285. pg{s<2:A,R}
  286.  
  287. ";
  288.         let workflows = parse(input);
  289.         let constraints = get_constraints(workflows);
  290.         let result = find_possibilities(constraints);
  291.         assert_eq!(result, 2);
  292.     }
  293.  
  294.     #[test]
  295.     fn test_input_4() {
  296.         let input = "in{x>3998:pb,x<3:pe,R}
  297. pb{m>3998:pc,R}
  298. pc{a>3998:pd,R}
  299. pd{s>3998:A,R}
  300. pe{m<3:pf,R}
  301. pf{a<3:pg,R}
  302. pg{s<3:A,R}
  303.  
  304. ";
  305.         let workflows = parse(input);
  306.         let constraints = get_constraints(workflows);
  307.         let result = find_possibilities(constraints);
  308.         assert_eq!(result, 32);
  309.     }
  310.  
  311.     #[test]
  312.     fn test_input_5() {
  313.         let input = "in{x>3998:pb,x>3998:pe,R}
  314. pb{m>3998:pc,R}
  315. pc{a>3998:pd,R}
  316. pd{s>3998:A,R}
  317. pe{m>3998:pf,R}
  318. pf{a>3998:pg,R}
  319. pg{s>3998:A,R}
  320.  
  321. ";
  322.         let workflows = parse(input);
  323.         let constraints = get_constraints(workflows);
  324.         let result = find_possibilities(constraints);
  325.         assert_eq!(result, 16);
  326.     }
  327.  
  328.     #[test]
  329.     fn test_parse() {
  330.         let input = TEST_INPUT;
  331.         parse(input);
  332.     }
  333.  
  334.     #[test]
  335.     fn test_parse_workflow() {
  336.         let input = "px{a<2006:qkq,m>2090:A,rfg}";
  337.         let workflow = Workflow::new(input);
  338.  
  339.         assert_eq!(workflow.name, "px");
  340.         assert_eq!(workflow.rules[0], Rule {
  341.             category: Some("a"),
  342.             operator: Operator::LT,
  343.             value: Some(2006),
  344.             target: "qkq",
  345.         });
  346.         assert_eq!(workflow.rules[1], Rule {
  347.             category: Some("m"),
  348.             operator: Operator::GT,
  349.             value: Some(2090),
  350.             target: "A",
  351.         });
  352.         assert_eq!(workflow.rules[2], Rule {
  353.             category: None,
  354.             operator: Operator::Immediate,
  355.             value: None,
  356.             target: "rfg",
  357.         });
  358.     }
  359.  
  360. }
Advertisement
Add Comment
Please, Sign In to add comment