160 Zeilen
4,4 KiB
Rust
160 Zeilen
4,4 KiB
Rust
|
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::*;
|
||
|
}
|