add day 7 solution

solved by claude.ai
This commit is contained in:
timeshifter
2026-06-13 17:54:34 +02:00
parent b8537ed049
commit 037c0d649c
2 changed files with 139 additions and 3 deletions
+139 -1
View File
@@ -1,5 +1,143 @@
use std::collections::HashMap;
// An operand is either a hard-coded 16-bit value or a reference to another wire.
#[derive(Debug, Clone)]
enum Operand {
Literal(u16),
Wire(String),
}
// Each gate variant carries its operand(s) as parsed from the instruction.
#[derive(Debug, Clone)]
enum Gate {
Signal(Operand),
Not(Operand),
And(Operand, Operand),
Or(Operand, Operand),
LShift(Operand, u16),
RShift(Operand, u16),
}
type Circuit = HashMap<String, Gate>;
// ── Parsing ────────────────────────────────────────────────────────────────────
fn parse_operand(s: &str) -> Operand {
match s.parse::<u16>() {
Ok(n) => Operand::Literal(n),
Err(_) => Operand::Wire(s.to_string()),
}
}
fn parse_line(line: &str) -> (String, Gate) {
let (expr, target) = line
.split_once(" -> ")
.expect("every line must contain ' -> '");
let tokens: Vec<&str> = expr.split_whitespace().collect();
let gate = match tokens.as_slice() {
[a] => Gate::Signal(parse_operand(a)),
["NOT", a] => Gate::Not(parse_operand(a)),
[a, "AND", b] => Gate::And(parse_operand(a), parse_operand(b)),
[a, "OR", b] => Gate::Or(parse_operand(a), parse_operand(b)),
[a, "LSHIFT", n] => Gate::LShift(parse_operand(a), n.parse().expect("shift amount")),
[a, "RSHIFT", n] => Gate::RShift(parse_operand(a), n.parse().expect("shift amount")),
_ => panic!("unrecognised expression: {expr}"),
};
(target.to_string(), gate)
}
// ── Evaluation ─────────────────────────────────────────────────────────────────
// Resolves a single operand: literals are returned as-is, wire names recurse
// into `evaluate`.
fn resolve(op: &Operand, circuit: &Circuit, cache: &mut HashMap<String, u16>) -> u16 {
match op {
Operand::Literal(n) => *n,
Operand::Wire(name) => evaluate(name, circuit, cache),
}
}
// Returns the 16-bit signal on `wire`, computing it recursively if not yet
// cached. The gate is cloned before recursing so that the immutable borrow
// of `circuit` is released before we mutably borrow `cache` deeper in the
// call stack — keeping the borrow checker happy without needing unsafe code.
fn evaluate(wire: &str, circuit: &Circuit, cache: &mut HashMap<String, u16>) -> u16 {
if let Some(&val) = cache.get(wire) {
return val;
}
let gate = circuit
.get(wire)
.unwrap_or_else(|| panic!("unknown wire: {wire}"))
.clone();
let val = match &gate {
Gate::Signal(a) => resolve(a, circuit, cache),
Gate::Not(a) => !resolve(a, circuit, cache),
Gate::And(a, b) => resolve(a, circuit, cache) & resolve(b, circuit, cache),
Gate::Or(a, b) => resolve(a, circuit, cache) | resolve(b, circuit, cache),
Gate::LShift(a, n) => resolve(a, circuit, cache) << n,
Gate::RShift(a, n) => resolve(a, circuit, cache) >> n,
};
cache.insert(wire.to_string(), val);
val
}
// ── Entry point ────────────────────────────────────────────────────────────────
fn main() {
println!("Hello, world!");
let input = std::fs::read_to_string("input.txt").expect("could not read input.txt");
let circuit: Circuit = input
.lines()
.filter(|l| !l.is_empty())
.map(parse_line)
.collect();
let mut cache: HashMap<String, u16> = HashMap::new();
println!("{}", evaluate("a", &circuit, &mut cache));
}
// ── Tests ──────────────────────────────────────────────────────────────────────
#[cfg(test)]
mod tests {
use super::*;
fn build_example_circuit() -> Circuit {
let src = "\
123 -> x
456 -> y
x AND y -> d
x OR y -> e
x LSHIFT 2 -> f
y RSHIFT 2 -> g
NOT x -> h
NOT y -> i";
src.lines().map(parse_line).collect()
}
#[test]
fn test_example_signals() {
let circuit = build_example_circuit();
let mut cache = HashMap::new();
// Evaluate every wire once; the cache is shared across all calls.
let get = |w: &str, cache: &mut HashMap<String, u16>| evaluate(w, &circuit, cache);
assert_eq!(get("d", &mut cache), 72);
assert_eq!(get("e", &mut cache), 507);
assert_eq!(get("f", &mut cache), 492);
assert_eq!(get("g", &mut cache), 114);
assert_eq!(get("h", &mut cache), 65412);
assert_eq!(get("i", &mut cache), 65079);
assert_eq!(get("x", &mut cache), 123);
assert_eq!(get("y", &mut cache), 456);
}
}
// https://adventofcode.com/2015/day/7