day19: problem 1 solution
This commit is contained in:
		
							
								
								
									
										239
									
								
								19/src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								19/src/main.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,239 @@
 | 
			
		||||
use std::collections::HashMap;
 | 
			
		||||
use std::fs::File;
 | 
			
		||||
use std::io::{BufRead, BufReader, Lines};
 | 
			
		||||
use std::time::Instant;
 | 
			
		||||
 | 
			
		||||
// BOILERPLATE
 | 
			
		||||
type InputIter = Lines<BufReader<File>>;
 | 
			
		||||
 | 
			
		||||
fn get_input() -> InputIter {
 | 
			
		||||
    let f = File::open("input").unwrap();
 | 
			
		||||
    let br = BufReader::new(f);
 | 
			
		||||
    br.lines()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    let start = Instant::now();
 | 
			
		||||
    let ans1 = problem1(get_input());
 | 
			
		||||
    let duration = start.elapsed();
 | 
			
		||||
    println!("Problem 1 solution: {} [{}s]", ans1, duration.as_secs_f64());
 | 
			
		||||
 | 
			
		||||
    let start = Instant::now();
 | 
			
		||||
    let ans2 = problem2(get_input());
 | 
			
		||||
    let duration = start.elapsed();
 | 
			
		||||
    println!("Problem 2 solution: {} [{}s]", ans2, duration.as_secs_f64());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DATA
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
struct RulePredicate {
 | 
			
		||||
    op: PredicateOperator,
 | 
			
		||||
    var: char,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
enum RuleAction {
 | 
			
		||||
    Terminate(bool),
 | 
			
		||||
    Jump(String),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<&str> for RuleAction {
 | 
			
		||||
    fn from(s: &str) -> Self {
 | 
			
		||||
        match s {
 | 
			
		||||
            "A" => Self::Terminate(true),
 | 
			
		||||
            "R" => Self::Terminate(false),
 | 
			
		||||
            s => Self::Jump(s.into()),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
struct Rule {
 | 
			
		||||
    pred: RulePredicate,
 | 
			
		||||
    action: RuleAction,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
enum PredicateOperator {
 | 
			
		||||
    Always,
 | 
			
		||||
    Lt(u64),
 | 
			
		||||
    Gt(u64),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<&str> for PredicateOperator {
 | 
			
		||||
    fn from(s: &str) -> Self {
 | 
			
		||||
        let (op_s, val_s) = s.split_at(1);
 | 
			
		||||
        match op_s {
 | 
			
		||||
            "<" => PredicateOperator::Lt(val_s.parse().unwrap()),
 | 
			
		||||
            ">" => PredicateOperator::Gt(val_s.parse().unwrap()),
 | 
			
		||||
            s => panic!("unknown operator {}", s),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<&str> for RulePredicate {
 | 
			
		||||
    fn from(s: &str) -> Self {
 | 
			
		||||
        let (var_s, pred_s) = s.split_at(1);
 | 
			
		||||
        Self {
 | 
			
		||||
            op: pred_s.into(),
 | 
			
		||||
            var: var_s.chars().next().unwrap(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl RulePredicate {
 | 
			
		||||
    fn check(&self, part: &Part) -> bool {
 | 
			
		||||
        match self.op {
 | 
			
		||||
            PredicateOperator::Always => true,
 | 
			
		||||
            PredicateOperator::Gt(val) => part.0[&self.var] > val,
 | 
			
		||||
            PredicateOperator::Lt(val) => part.0[&self.var] < val,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<&str> for Rule {
 | 
			
		||||
    fn from(s: &str) -> Self {
 | 
			
		||||
        println!("parsing {}", s);
 | 
			
		||||
        if let Some((predicate_s, action_s)) = s.split_once(':') {
 | 
			
		||||
            Self {
 | 
			
		||||
                pred: predicate_s.into(),
 | 
			
		||||
                action: action_s.into(),
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            Self {
 | 
			
		||||
                pred: RulePredicate {
 | 
			
		||||
                    op: PredicateOperator::Always,
 | 
			
		||||
                    var: '\0',
 | 
			
		||||
                },
 | 
			
		||||
                action: s.into(),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
struct Workflow {
 | 
			
		||||
    name: String,
 | 
			
		||||
    rules: Vec<Rule>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<&str> for Workflow {
 | 
			
		||||
    fn from(s: &str) -> Self {
 | 
			
		||||
        let (name_s, rest_s) = s.split_once('{').unwrap();
 | 
			
		||||
        println!("name: {} rest: {}", name_s, rest_s);
 | 
			
		||||
        let rules = rest_s.split_once('}').unwrap().0.split(',').map(|r| r.into()).collect();
 | 
			
		||||
        Self {
 | 
			
		||||
            name: name_s.into(),
 | 
			
		||||
            rules,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
impl Workflow {
 | 
			
		||||
    fn execute(&self, part: &Part) -> RuleAction {
 | 
			
		||||
        for r in &self.rules {
 | 
			
		||||
            if r.pred.check(part) {
 | 
			
		||||
                return r.action.clone()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        panic!("unhandled part {:?}", part);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Workflows {
 | 
			
		||||
    fn execute(&self, part: &Part) -> bool {
 | 
			
		||||
        let mut action = RuleAction::Jump("in".into());
 | 
			
		||||
        loop {
 | 
			
		||||
            match &action {
 | 
			
		||||
                RuleAction::Terminate(b) => return *b,
 | 
			
		||||
                RuleAction::Jump(j) => {
 | 
			
		||||
                    let next_workflow = &self.0[j];
 | 
			
		||||
                    action = next_workflow.execute(part)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
struct Workflows(HashMap<String, Workflow>);
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
struct Part(HashMap<char, u64>);
 | 
			
		||||
 | 
			
		||||
impl From<&str> for Part {
 | 
			
		||||
    fn from(s: &str) -> Self {
 | 
			
		||||
        let (_, vars_s) = s.split_once('{').unwrap();
 | 
			
		||||
        let vars = vars_s.split_once('}').unwrap().0.split(',');
 | 
			
		||||
        let mut part = HashMap::new();
 | 
			
		||||
        for var in vars {
 | 
			
		||||
            let (name, val) = var.split_once('=').unwrap();
 | 
			
		||||
            part.insert(name.chars().next().unwrap(), val.parse().unwrap());
 | 
			
		||||
        }
 | 
			
		||||
        Self(part)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Parts = Vec<Part>;
 | 
			
		||||
 | 
			
		||||
// PROBLEM 1 solution
 | 
			
		||||
 | 
			
		||||
fn problem1<T: BufRead>(mut input: Lines<T>) -> u64 {
 | 
			
		||||
    let mut wfs = Workflows(HashMap::new());
 | 
			
		||||
    let mut parts: Parts = Vec::new();
 | 
			
		||||
    while let Some(Ok(line)) = input.next() {
 | 
			
		||||
        println!("line: {}", line);
 | 
			
		||||
        if line != "" {
 | 
			
		||||
            let wf: Workflow = line.as_str().into();
 | 
			
		||||
            wfs.0.insert(wf.name.clone(), wf);
 | 
			
		||||
        } else {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    while let Some(Ok(line)) = input.next() {
 | 
			
		||||
        parts.push(line.as_str().into());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    parts.iter().filter(|part| wfs.execute(part)).map(|part| part.0.values().sum::<u64>()).sum::<u64>()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PROBLEM 2 solution
 | 
			
		||||
fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
 | 
			
		||||
    0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use crate::*;
 | 
			
		||||
    use std::io::Cursor;
 | 
			
		||||
 | 
			
		||||
    const EXAMPLE: &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 problem1_example() {
 | 
			
		||||
        let c = Cursor::new(EXAMPLE);
 | 
			
		||||
        assert_eq!(problem1(c.lines()), 19114);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn problem2_example() {
 | 
			
		||||
        let c = Cursor::new(EXAMPLE);
 | 
			
		||||
        assert_eq!(problem2(c.lines()), 0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user