[ prog / sol / mona ]

prog


Test

1 2021-05-22 11:47
use std::{
    collections::HashMap,
    ops::{BitAnd, BitOr, Not, Shl, Shr},
    str::FromStr,
    time::Instant,
};

trait BitOp {
    fn is_bitop(&self) -> bool;
    fn not_bitop(&self) -> bool;
}

impl BitOp for &str {
    fn is_bitop(&self) -> bool {
        matches!(*self, "AND" | "OR" | "NOT" | "LSHIFT" | "RSHIFT")
    }
    fn not_bitop(&self) -> bool {
        !self.is_bitop()
    }
}

fn ops(arg: &str) -> impl Iterator<Item = &str> {
    arg.split_ascii_whitespace().filter(BitOp::is_bitop)
}

fn idents(arg: &str) -> impl Iterator<Item = &str> {
    arg.split_ascii_whitespace().filter(BitOp::not_bitop)
}

struct Circuit<T> {
    connections: HashMap<String, String>,
    cache: HashMap<String, T>,
}

impl<T> Circuit<T>
where
    T: FromStr
        + Not<Output = T>
        + BitAnd<Output = T>
        + BitOr<Output = T>
        + Shl<Output = T>
        + Shr<Output = T>
        + Copy,
{
    fn new() -> Self {
        Self {
            connections: HashMap::new(),
            cache: HashMap::new(),
        }
    }

    fn add_connection(&mut self, arg: &str) {
        let split = arg.trim().split_once(" -> ").unwrap();
        self.connections
            .insert(split.1.to_string(), split.0.to_string());
    }

    fn get(&mut self, expr: &str) -> T {
        if let Some(n) = self.cache.get(expr) {
            *n
        } else {
            let n: T = {
                let mut op_stream = ops(expr);
                let mut ident_stream = idents(expr);
                match (op_stream.next(), ident_stream.next(), ident_stream.next()) {
                    (None, Some(ident), None) => match ident.parse() {
                        Ok(n) => n,
                        _ => {
                            let expr = self.connections.get(ident).unwrap().clone();
                            self.get(&expr)
                        }
                    },
                    (Some(op), Some(lhs), _) if op == "NOT" => !self.get(lhs),
                    (Some(op), Some(lhs), Some(rhs)) => {
                        let lhs = self.get(lhs);
                        let rhs = self.get(rhs);
                        match op {
                            "AND" => lhs & rhs,
                            "OR" => lhs | rhs,
                            "LSHIFT" => lhs << rhs,
                            "RSHIFT" => lhs >> rhs,
                            _ => unreachable!(),
                        }
                    }
                    _ => unreachable!(),
                }
            };
            self.cache.insert(expr.to_string(), n);
            n
        }
    }
}

pub fn d7() {
    let time = Instant::now();
    let arg = include_str!("../data/d7.txt");
    let mut circuit = Circuit::<u16>::new();
    for line in arg.lines() {
        circuit.add_connection(line);
    }
    let p1 = circuit.get("a");
    circuit
        .connections
        .insert(String::from("b"), p1.to_string());
    circuit.cache.clear();
    circuit.cache.insert(String::from("b"), p1);
    let p2 = circuit.get("a");

    println!("Day 7: p1: {}, p2: {}, time: {:?}", p1, p2, time.elapsed());
}
5


VIP:

do not edit these