puzzles/advent_of_code_2015/src/day7/part1.rs
2025-12-07 18:18:40 +01:00

102 lines
3.2 KiB
Rust

use std::collections::HashMap;
#[derive(Debug, Clone)]
pub enum Value {
Literal(u16),
Identifier(String),
}
#[derive(Debug, Clone, Copy)]
pub enum Operator {
And,
Or,
RShift,
LShift,
Not
}
#[derive(Debug, Clone)]
pub enum Expression {
Assign(Value), // 1 token before arrow
Binary(Operator, Value, Value), // 3 tokens before arrow
Unary(Value), // always not // 2 tokens before arrow
}
fn parse_operator(name: &str) -> Operator {
match name {
"AND" => Operator::And,
"OR" => Operator::Or,
"RSHIFT" => Operator::RShift,
"LSHIFT" => Operator::LShift,
_ => panic!("unexpected operator: {}", name)
}
}
fn parse_value(value: &str) -> Value {
if let Ok(num) = value.parse::<u16>() {
Value::Literal(num)
} else {
Value::Identifier(value.into())
}
}
fn solve_value(value: &Value, expressions: &HashMap<String, Expression>, cache: &mut HashMap<String, u16>) -> u16 {
match value {
Value::Literal(num) => *num,
Value::Identifier(name) => {
let result = calculate_wire(name, expressions, cache);
cache.insert(name.clone(), result);
result
},
}
}
fn calculate_wire(ident: &String, expressions: &HashMap<String, Expression>, cache: &mut HashMap<String, u16>) -> u16 {
if let Some(num) = cache.get(ident) {
return *num;
}
match expressions.get(ident).unwrap() {
Expression::Assign(value) => {
solve_value(value, expressions, cache)
},
Expression::Binary(operator, lhs, rhs) => {
match operator {
Operator::And => solve_value(lhs, expressions, cache) & solve_value(rhs, expressions, cache),
Operator::Or => solve_value(lhs, expressions, cache) | solve_value(rhs, expressions, cache),
Operator::RShift => solve_value(lhs, expressions, cache) >> solve_value(rhs, expressions, cache),
Operator::LShift => solve_value(lhs, expressions, cache) << solve_value(rhs, expressions, cache),
Operator::Not => todo!(),
}
},
Expression::Unary(value) => {
!solve_value(value, expressions, cache)
},
}
}
pub fn solve(input: &str) {
let mut value_cache: HashMap<String, u16> = HashMap::new();
let expressions = input.lines().map(|line| {
let (expr, into) = line.split_once(" -> ").unwrap();
let parts = expr.split(" ").collect::<Vec<_>>();
let parsed = match parts.len() {
1 => { // assignment
Expression::Assign(parse_value(expr))
},
2 => {
Expression::Unary(parse_value(parts[1]))
},
3 => {
Expression::Binary(parse_operator(parts[1]), parse_value(parts[0]), parse_value(parts[2]))
},
_ => panic!("unexpected number of parts: {line}")
};
// println!("parsed: {into} -> {parsed:?}");
(into.to_string(), parsed)
}).collect::<HashMap<_, _>>();
println!("solve for a: {}", calculate_wire(&"a".into(), &expressions, &mut value_cache));
}