adventofcode/days/2024/17.rs

169 Zeilen
4,7 KiB
Rust

2024-12-17 13:38:02 +01:00
use advent_of_code::strings::{convert_to_array, parsenumber};
use advent_of_code_macros::include_aoc;
2024-12-17 22:16:01 +01:00
use log::*;
2024-12-17 13:38:02 +01:00
use thousands::Separable;
include_aoc!(DATA 2024 17);
2024-12-17 13:38:02 +01:00
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!(),
}
}
2024-12-17 22:16:01 +01:00
fn reset(&mut self) {
self.a = 0;
self.b = 0;
self.c = 0;
self.pos = 0;
self.output.clear();
}
2024-12-17 13:38:02 +01:00
}
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;
2024-12-17 22:16:01 +01:00
'numloop: for (pos, num) in mem.ops.iter().enumerate().map(|(x, y)| (x * 3, *y)).rev() {
for i in 0..64 {
println!("Testing round({}) == {}", ((n >> pos) + i).separate_with_underscores(), num);
if round((n >> pos) + i) == num {
println!("Adding {}, the source of {}", i, num);
2024-12-17 13:38:02 +01:00
n += i << pos;
continue 'numloop;
}
}
println!("Not Possible to find equivalent of {}", num);
}
2024-12-17 22:16:01 +01:00
println!("Testing {}", format!("{:018b}", n).separate_with_dots());
if n >= 48331947862051 {
println!("Failed");
return;
}
mem.reset();
2024-12-17 13:38:02 +01:00
mem.a = n;
mem.generic_process();
if mem.output == mem.ops {
println!("A: {n}")
} else {
println!("{:?}\n{:?}", mem.ops, mem.output);
}
}
#[cfg(test)]
mod test {
use super::*;
}