~cdv/aoc-2021

01cdaf69328eaa79adc9377cdb0ac9fe1a9d52dd — Chris Vittal 2 years ago 39366f5
rs: day 24

super sloooooooowwwwwww ugh
2 files changed, 442 insertions(+), 2 deletions(-)

A input/day_24.txt
M rs/src/bin/day24/main.rs
A input/day_24.txt => input/day_24.txt +252 -0
@@ 0,0 1,252 @@
inp w
mul x 0
add x z
mod x 26
div z 1
add x 13
eql x w
eql x 0
mul y 0
add y 25
mul y x
add y 1
mul z y
mul y 0
add y w
add y 14
mul y x
add z y
inp w
mul x 0
add x z
mod x 26
div z 1
add x 12
eql x w
eql x 0
mul y 0
add y 25
mul y x
add y 1
mul z y
mul y 0
add y w
add y 8
mul y x
add z y
inp w
mul x 0
add x z
mod x 26
div z 1
add x 11
eql x w
eql x 0
mul y 0
add y 25
mul y x
add y 1
mul z y
mul y 0
add y w
add y 5
mul y x
add z y
inp w
mul x 0
add x z
mod x 26
div z 26
add x 0
eql x w
eql x 0
mul y 0
add y 25
mul y x
add y 1
mul z y
mul y 0
add y w
add y 4
mul y x
add z y
inp w
mul x 0
add x z
mod x 26
div z 1
add x 15
eql x w
eql x 0
mul y 0
add y 25
mul y x
add y 1
mul z y
mul y 0
add y w
add y 10
mul y x
add z y
inp w
mul x 0
add x z
mod x 26
div z 26
add x -13
eql x w
eql x 0
mul y 0
add y 25
mul y x
add y 1
mul z y
mul y 0
add y w
add y 13
mul y x
add z y
inp w
mul x 0
add x z
mod x 26
div z 1
add x 10
eql x w
eql x 0
mul y 0
add y 25
mul y x
add y 1
mul z y
mul y 0
add y w
add y 16
mul y x
add z y
inp w
mul x 0
add x z
mod x 26
div z 26
add x -9
eql x w
eql x 0
mul y 0
add y 25
mul y x
add y 1
mul z y
mul y 0
add y w
add y 5
mul y x
add z y
inp w
mul x 0
add x z
mod x 26
div z 1
add x 11
eql x w
eql x 0
mul y 0
add y 25
mul y x
add y 1
mul z y
mul y 0
add y w
add y 6
mul y x
add z y
inp w
mul x 0
add x z
mod x 26
div z 1
add x 13
eql x w
eql x 0
mul y 0
add y 25
mul y x
add y 1
mul z y
mul y 0
add y w
add y 13
mul y x
add z y
inp w
mul x 0
add x z
mod x 26
div z 26
add x -14
eql x w
eql x 0
mul y 0
add y 25
mul y x
add y 1
mul z y
mul y 0
add y w
add y 6
mul y x
add z y
inp w
mul x 0
add x z
mod x 26
div z 26
add x -3
eql x w
eql x 0
mul y 0
add y 25
mul y x
add y 1
mul z y
mul y 0
add y w
add y 7
mul y x
add z y
inp w
mul x 0
add x z
mod x 26
div z 26
add x -2
eql x w
eql x 0
mul y 0
add y 25
mul y x
add y 1
mul z y
mul y 0
add y w
add y 13
mul y x
add z y
inp w
mul x 0
add x z
mod x 26
div z 26
add x -14
eql x w
eql x 0
mul y 0
add y 25
mul y x
add y 1
mul z y
mul y 0
add y w
add y 3
mul y x
add z y

M rs/src/bin/day24/main.rs => rs/src/bin/day24/main.rs +190 -2
@@ 1,7 1,195 @@
use aoc2021::*;
use std::ops::*;

fn solve(_input: String) -> Result<(impl Display, impl Display)> {
    Ok((NYI, NYI))
#[derive(Debug, Clone, Copy)]
enum Reg {
    X = 0,
    Y = 1,
    Z = 2,
    W = 3,
}

impl FromStr for Reg {
    type Err = eyre::Report;
    fn from_str(reg: &str) -> Result<Self> {
        match reg {
            "x" => Ok(Self::X),
            "y" => Ok(Self::Y),
            "z" => Ok(Self::Z),
            "w" => Ok(Self::W),
            _ => Err(eyre::eyre!("not a register: {:?}", reg)),
        }
    }
}

impl Index<Reg> for Alu {
    type Output = i64;
    fn index(&self, reg: Reg) -> &i64 {
        self.regs.get(reg as usize).unwrap()
    }
}

impl IndexMut<Reg> for Alu {
    fn index_mut(&mut self, reg: Reg) -> &mut i64 {
        self.regs.get_mut(reg as usize).unwrap()
    }
}

#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
struct Alu {
    regs: [i64; 4],
}

impl Alu {
    fn inp(&mut self, tgt: Reg, val: i64) {
        self[tgt] = val;
    }

    fn binop(&mut self, op: Inst) {
        let (op, tgt, val): (fn(i64, i64) -> i64, _, _) = match op {
            Inst::Add(tgt, val) => (|a, b| a + b, tgt, val),
            Inst::Mul(tgt, val) => (|a, b| a * b, tgt, val),
            Inst::Div(tgt, val) => (|a, b| a / b, tgt, val),
            Inst::Mod(tgt, val) => (|a, b| a % b, tgt, val),
            Inst::Eql(tgt, val) => {
                match val {
                    Value::Imm(v) => self[tgt] = (self[tgt] == v) as i64,
                    Value::Reg(r) => self[tgt] = (self[tgt] == self[r]) as i64,
                }
                return;
            }
            _ => unreachable!(),
        };

        match val {
            Value::Imm(v) => self[tgt] = op(self[tgt], v),
            Value::Reg(r) => self[tgt] = op(self[tgt], self[r]),
        }
    }
}

#[derive(Debug, Clone, Copy)]
enum Value {
    Imm(i64),
    Reg(Reg),
}

impl FromStr for Value {
    type Err = eyre::Report;
    fn from_str(val: &str) -> Result<Self> {
        match val.parse::<Reg>() {
            Ok(reg) => Ok(Self::Reg(reg)),
            Err(_) => Ok(Self::Imm(
                val.parse()
                    .wrap_err_with(|| eyre::eyre!("not a value: {:?}", val))?,
            )),
        }
    }
}

#[derive(Debug, Clone, Copy)]
enum Inst {
    Inp(Reg),
    Add(Reg, Value),
    Mul(Reg, Value),
    Div(Reg, Value),
    Mod(Reg, Value),
    Eql(Reg, Value),
}

impl FromStr for Inst {
    type Err = eyre::Report;
    fn from_str(inst: &str) -> Result<Self> {
        let err = || eyre::eyre!("invalid instruction: {:?}", inst);
        let (inst, ops) = inst.split_once(' ').ok_or_else(err)?;
        let ctor = match inst {
            "inp" => {
                let reg = ops.parse().wrap_err_with(err)?;
                return Ok(Self::Inp(reg));
            }
            "add" => Self::Add,
            "mul" => Self::Mul,
            "div" => Self::Div,
            "mod" => Self::Mod,
            "eql" => Self::Eql,
            _ => return Err(err()),
        };

        let (reg, val) = ops.split_once(' ').ok_or_else(err)?;
        Ok(ctor(
            reg.parse().wrap_err_with(err)?,
            val.parse().wrap_err_with(err)?,
        ))
    }
}

fn run<const SMALLEST: bool>(
    prog: &[Inst], pc: usize, alu: Alu, memo: &mut HashMap<(usize, Alu), Option<i64>>,
) -> Option<i64> {
    assert!(matches!(prog[pc], Inst::Inp(_)));
    if let Some(&ans) = memo.get(&(pc, alu)) {
        return ans;
    }

    let range = if SMALLEST {
        [1, 2, 3, 4, 5, 6, 7, 8, 9]
    } else {
        [9, 8, 7, 6, 5, 4, 3, 2, 1]
    };

    'outer: for inp_val in range {
        let (mut alu, mut pc) = (alu, pc);
        if let Inst::Inp(reg) = prog[pc] {
            alu.inp(reg, inp_val);
            pc += 1;
        } else {
            unreachable!()
        };

        while let Some(inst) = prog.get(pc) {
            if let Inst::Inp(_) = inst {
                match run::<SMALLEST>(prog, pc, alu, memo) {
                    Some(res) => {
                        memo.insert((pc, alu), Some(res * 10 + inp_val));
                        return Some(res * 10 + inp_val);
                    }
                    None => continue 'outer,
                }
            } else {
                alu.binop(*inst);
                pc += 1;
            }
        }

        if alu[Reg::Z] == 0 {
            memo.insert((pc, alu), Some(inp_val));
            return Some(inp_val);
        }
    }

    memo.insert((pc, alu), None);
    None
}

fn solve(input: String) -> Result<(impl Display, impl Display)> {
    let prog: Vec<Inst> = input.to_collection()?;
    assert!(matches!(prog[0], Inst::Inp(_)));

    let mut memo = HashMap::new();
    let ans = run::<false>(&prog, 0, Alu::default(), &mut memo);

    let one = format!("{}", ans.unwrap())
        .chars()
        .rev()
        .collect::<String>();

    let ans = run::<true>(&prog, 0, Alu::default(), &mut memo);
    let two = format!("{}", ans.unwrap())
        .chars()
        .rev()
        .collect::<String>();

    Ok((one, two))
}

fn main() -> Result<()> {