adventofcode/days/2024/17.rs

160 Zeilen
4,4 KiB
Rust

2024-12-17 13:38:02 +01:00
use advent_of_code::strings::{convert_to_array, parsenumber};
#[allow(unused_imports)]
use advent_of_code_macros::{include_data, include_example};
use log::debug;
use thousands::Separable;
include_data!(DATA 2024 17);
const ADV: u64 = 0;
const BXL: u64 = 1;
const BST: u64 = 2;
const JNZ: u64 = 3;
const BXC: u64 = 4;
const OUT: u64 = 5;
const BDV: u64 = 6;
const CDV: u64 = 7;
const BASE: u64 = 2;
#[derive(Debug, Clone)]
struct GenericCPU {
a: u64,
b: u64,
c: u64,
pos: usize,
ops: Vec<u64>,
output: Vec<u64>,
}
impl GenericCPU {
fn generic_process(&mut self) {
let mut opcode;
let mut operand;
loop {
opcode = match self.ops.get(self.pos) {
None => break,
Some(x) => *x,
};
operand = *self.ops.get(self.pos + 1).unwrap();
match opcode {
ADV => {
debug!("truncating A({}) >> {} = {}", self.a, self.comboop(operand), self.a >> self.comboop(operand));
self.a >>= self.comboop(operand);
},
BXL => {
debug!("XOR B({}) with {} = {}", self.b, operand, self.b ^ operand);
self.b ^= operand;
},
BST => {
self.b = self.comboop(operand) % 8;
debug!("Setting B to comboop({}) = ({})", operand, self.b)
},
JNZ => {
if self.a != 0 {
debug!("Jumping to {}", operand);
self.pos = operand as usize;
continue;
}
debug!("Do nothing");
},
BXC => {
debug!("XORing B and C");
self.b ^= self.c;
},
OUT => {
debug!("printing {} % 8 = {}", self.comboop(operand), self.comboop(operand) % 8);
self.output.push(self.comboop(operand) % 8);
},
BDV => {
debug!("truncating A({}) >> {} = B({})", self.a, self.comboop(operand), self.a >> self.comboop(operand));
self.b = self.a >> self.comboop(operand);
},
CDV => {
debug!("truncating A({}) >> {} = C({})", self.a, self.comboop(operand), self.a >> self.comboop(operand));
self.c = self.a >> self.comboop(operand);
},
x => {
debug!("opcode {x} unimplemented");
break;
},
}
self.pos += 2;
}
}
fn comboop(&self, op: u64) -> u64 {
match op {
0..=3 => op,
4 => self.a,
5 => self.b,
6 => self.c,
7 => unimplemented!(),
_ => unreachable!(),
}
}
}
fn get_content(i: &str) -> String {
if i == "" {
i.to_string()
} else {
i.split_once(':').unwrap().1.trim().to_string()
}
}
fn round(n: u64) -> u64 {
let mut b = n % 8;
b ^= 6;
b ^= n >> b;
b ^= 7;
b % 8
}
fn main() {
let data = convert_to_array::<_, _, '\n'>(DATA, get_content);
let mut mem = GenericCPU {
a: parsenumber(&data[0]),
b: parsenumber(&data[1]),
c: parsenumber(&data[2]),
pos: 0,
ops: data[4].split(',').map(|op| parsenumber(op)).collect(),
output: Vec::new(),
};
let mut n = mem.a;
while n > 0 {
println!("Round: {}", round(n));
n >>= 3;
}
mem.generic_process();
let output = mem.output.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",");
println!("output: {}", output);
let mut n: u64 = 0;
'numloop: for (pos, num) in mem.ops.iter().cloned().enumerate().map(|(x, y)| (x * 3, y)) {
for i in 0..8 {
if round(i) == num {
println!("Adding {:>18}, the source of {}", i, num);
n += i << pos;
continue 'numloop;
}
}
println!("Not Possible to find equivalent of {}", num);
}
println!("Testing {}", n);
mem.a = n;
mem.b = 0;
mem.c = 0;
mem.pos = 0;
mem.output.clear();
mem.generic_process();
if mem.output == mem.ops {
println!("A: {n}")
} else {
println!("{:?}\n{:?}", mem.ops, mem.output);
}
}
#[cfg(test)]
mod test {
use super::*;
}