day 17 was a doozy

This commit is contained in:
Shoofle 2024-12-17 12:33:44 -05:00
parent 534ebef096
commit 5f0d6f9869
2 changed files with 263 additions and 0 deletions

6
day17/Cargo.toml Normal file
View File

@ -0,0 +1,6 @@
[package]
name = "day17"
version = "0.1.0"
edition = "2021"
[dependencies]

257
day17/src/main.rs Normal file
View File

@ -0,0 +1,257 @@
use std::collections::HashSet;
use std::collections::HashMap;
use std::env;
use std::fs;
fn main() {
println!("Hello, AoC day 13!");
let args: Vec<String> = env::args().collect();
if args.len() != 2 {
println!("wrong number of arguments!");
std::process::exit(1);
}
let file_path = &args[1];
let binding = fs::read_to_string(file_path)
.expect("should be able to read the file");
let mut register: [u128; 3] = [0,0,0];
let mut program: Vec<u8> = Vec::new();
let mut instruction_pointer: usize = 0;
let mut stdout: Vec<u8> = Vec::new();
for line in binding.lines() {
if line.contains("Register A: ") {
register[0] = line.replace("Register A: ", "").parse().unwrap();
}
if line.contains("Register B: ") {
register[1] = line.replace("Register B: ", "").parse().unwrap();
}
if line.contains("Register B: ") {
register[2] = line.replace("Register B: ", "").parse().unwrap();
}
if line.contains("Program: ") {
program = line.replace("Program: ", "")
.split(",")
.map(|x| x.parse().unwrap())
.collect();
}
}
println!("initial state:");
print_state(&register, &program, &instruction_pointer);
// part a
print!("program output: ");
while let Ok(result) = step(&mut register, &program, &mut instruction_pointer) {
if let Some(output) = result {
stdout.push(output);
}
}
println!("{stdout:?}");
println!("");
// part b
let mut head = vec![0_u128];
let mut suffixes: HashMap<u128, Vec<u8>> = HashMap::new();
let mut winners: HashSet<u128> = HashSet::new();
while let Some(prefix) = head.pop() {
let desired;
if prefix == 0 {
desired = program[program.len()-1];
} else {
let length = format!("{prefix:o}").len();
if length >= program.len() {
winners.insert(prefix);
continue;
}
desired = program[program.len() - length - 1]
}
if suffixes.contains_key(&prefix) { continue; }
let octets = find_octets(prefix, desired);
for x in &octets {
head.push((prefix << 3) + (*x as u128));
}
suffixes.insert(prefix, octets);
}
let mut smallest = u128::MAX;
for winner in winners {
if winner < smallest {
smallest = winner;
}
}
println!("the smallest quining initial value was {smallest} ");
register[0] = smallest;
register[1] = 0;
register[2] = 0;
instruction_pointer = 0;
stdout.drain(..);
println!("program output: ");
while let Ok(result) = step(&mut register, &program, &mut instruction_pointer) {
if let Some(output) = result {
stdout.push(output);
}
}
println!("{program:?}");
println!("{stdout:?}");
}
fn step(
register: &mut [u128; 3],
program: &Vec<u8>,
instruction_pointer: &mut usize)
-> Result<Option<u8>, ()> {
if *instruction_pointer >= program.len() { return Err(()); }
let instruction = program[*instruction_pointer];
if *instruction_pointer + 1 >= program.len() { return Err(()); }
let operand = program[*instruction_pointer + 1];
let literal_operand = operand;
let combo_operand = match operand {
4 => register[0],
5 => register[1],
6 => register[2],
anything => anything.into(),
};
let mut output: Option<u8> = None;
*instruction_pointer += 2;
/*
println!("executing {} {}",
match instruction {0=>"adv",1=>"bxl",2=>"bst",3=>"jnz",4=>"bxc",5=>"out",6=>"bdv",7=>"cdv",_=>"???"},
literal_operand);
*/
match instruction {
0 => { register[0] = div_thing(register[0], combo_operand); }, // adv
1 => { register[1] = register[1] ^ (literal_operand as u128); }, // bxl
2 => { register[1] = combo_operand % 8; }, // bst
3 => match register[0] { // jnz
0 => {},
_ => { *instruction_pointer = literal_operand as usize; }
},
4 => { register[1] = register[1] ^ register[2]; }, // bxc
5 => { output = Some((combo_operand % 8) as u8); }, // out
6 => { register[1] = div_thing(register[0], combo_operand); }, // bdv
7 => { register[2] = div_thing(register[0], combo_operand); }, // cdv
_ => { return Err(()); },
}
return Ok(output);
}
fn div_thing(a: u128, b: u128) -> u128 {
let power = 2_u128.pow(b.try_into().unwrap());
return a / power;
}
fn print_state(register: &[u128;3], program: &Vec<u8>, instruction_pointer: &usize) {
println!("registers: {register:?}");
println!("program: {program:?}");
println!("current pointer: {instruction_pointer}");
}
/*
2 bst -> modulo combo operand => B
4 bxc -> B xor C => B
1 bxl -> B xor literal operand => B
4 bxc -> B xor C => B
7 cdv -> A / 2^(combo operand) => C
5 out -> print combo operand
4 bxc -> B xor C => B
1 bxl -> B xor literal operand => B
1 bxl -> B xor literal operand => B
4 bxc -> B xor C => B
5 out => print combo operand
5 out => print combo operand
0 adv => A / 2^(combo operand) => A
3 jnz => jump literal operand if A != 0
3 jnz => jump literal operand if A != 0
0 adv => A / 2^(combo operand) => A
2,4,1,4,7,5,4,1,1,4,5,5,0,3,3,0
there is only one JNZ executed in the normal execution, and it goes to the start.
all instructions are always aligned.
2 bst -> A % 8 => B
1 bxl -> B xor 4 => B
7 cdv -> A / 2^B => C
4 bxc -> B xor C => B
1 bxl -> B xor 4 => B
5 out => print B
0 adv => A / 2^3 => A
halt if A == 0, otherwise repeat
B = X % 8
B = B xor 4 // flip byte 3 (4's position)
C = A >> B
B = B xor C
B = B xor 4 // flip byte 3
print B
A = A / 2^3
treat A as a sequence of octets
0o7654321
_111_110_101_100_011_010_001
B = 001
B = 001 xor 100 = 101 = 0d5
C = _111_110_101_100_011_010_001 >> 5 = 001_111_101_011_000_110
B = B xor C = 101 xor 001_111_101_011_000_110 = 001_111_101_011_000_011
print 011 = 0d3
A = A >> 3
last octet we want to output is 0 = 000
X = 000...ijk
B=ijk
B = i j k xor 4 => ~i j k
C = i j k >> ~i j k
B = ~i j k xor C
B = B xor 4
print B
*/
fn find_octets(prefix: u128, target: u8) -> Vec<u8> {
// returns all suffixes such that (prefix << 3) + suffix produces target as the output
let mut suffixes: Vec<u8> = Vec::with_capacity(3);
for candidate in 0..8_u8 {
let a = (prefix << 3) + (candidate as u128);
let mut b = a % 8;
b = b ^ 4;
let c = a >> b;
b = b ^ c;
b = b ^ 4;
if b % 8 == target.into() {
suffixes.push(candidate);
}
}
suffixes
}