This commit is contained in:
parent
5bcead2691
commit
9be86e2cc2
89
src/day17.rs
89
src/day17.rs
@ -1,5 +1,3 @@
|
|||||||
use std::{ops::BitXor, str::FromStr};
|
|
||||||
|
|
||||||
use aoc_runner_derive::aoc;
|
use aoc_runner_derive::aoc;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
@ -23,27 +21,27 @@ impl From<usize> for Register {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum Opcode {
|
enum Opcode {
|
||||||
adv = 0,
|
Adv = 0,
|
||||||
bxl = 1,
|
Bxl = 1,
|
||||||
bst = 2,
|
Bst = 2,
|
||||||
jnz = 3,
|
Jnz = 3,
|
||||||
bxc = 4,
|
Bxc = 4,
|
||||||
out = 5,
|
Out = 5,
|
||||||
bdv = 6,
|
Bdv = 6,
|
||||||
cdv = 7,
|
Cdv = 7,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<i64> for Opcode {
|
impl From<i64> for Opcode {
|
||||||
fn from(value: i64) -> Self {
|
fn from(value: i64) -> Self {
|
||||||
match value {
|
match value {
|
||||||
0 => Opcode::adv,
|
0 => Opcode::Adv,
|
||||||
1 => Opcode::bxl,
|
1 => Opcode::Bxl,
|
||||||
2 => Opcode::bst,
|
2 => Opcode::Bst,
|
||||||
3 => Opcode::jnz,
|
3 => Opcode::Jnz,
|
||||||
4 => Opcode::bxc,
|
4 => Opcode::Bxc,
|
||||||
5 => Opcode::out,
|
5 => Opcode::Out,
|
||||||
6 => Opcode::bdv,
|
6 => Opcode::Bdv,
|
||||||
7 => Opcode::cdv,
|
7 => Opcode::Cdv,
|
||||||
v => panic!("invalid opcode {}", v),
|
v => panic!("invalid opcode {}", v),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -52,9 +50,9 @@ impl From<i64> for Opcode {
|
|||||||
impl Opcode {
|
impl Opcode {
|
||||||
fn interp_operand(&self, value: i64) -> Operand {
|
fn interp_operand(&self, value: i64) -> Operand {
|
||||||
match self {
|
match self {
|
||||||
Self::adv | Self::bst | Self::out | Self::bdv | Self::cdv => Operand::new_combo(value),
|
Self::Adv | Self::Bst | Self::Out | Self::Bdv | Self::Cdv => Operand::new_combo(value),
|
||||||
Self::bxl | Self::jnz => Operand::Literal(value),
|
Self::Bxl | Self::Jnz => Operand::Literal(value),
|
||||||
Self::bxc => Operand::Ignore,
|
Self::Bxc => Operand::Ignore,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,12 +82,6 @@ impl Operand {
|
|||||||
Self::Ignore => panic!("can't read ignored operand"),
|
Self::Ignore => panic!("can't read ignored operand"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn is_literal(self) -> bool {
|
|
||||||
match self {
|
|
||||||
Self::Literal(_) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -118,16 +110,14 @@ struct Instruction {
|
|||||||
impl Instruction {
|
impl Instruction {
|
||||||
fn exec(&self, m: &mut Machine) {
|
fn exec(&self, m: &mut Machine) {
|
||||||
match self.opcode {
|
match self.opcode {
|
||||||
Opcode::adv => self.adv(m),
|
Opcode::Adv => self.adv(m),
|
||||||
Opcode::bxl => self.bxl(m),
|
Opcode::Bxl => self.bxl(m),
|
||||||
Opcode::bst => self.bst(m),
|
Opcode::Bst => self.bst(m),
|
||||||
Opcode::jnz => self.jnz(m),
|
Opcode::Jnz => self.jnz(m),
|
||||||
Opcode::bxc => self.bxc(m),
|
Opcode::Bxc => self.bxc(m),
|
||||||
Opcode::out => self.out(m),
|
Opcode::Out => self.out(m),
|
||||||
Opcode::bdv => self.bdv(m),
|
Opcode::Bdv => self.bdv(m),
|
||||||
Opcode::cdv => self.cdv(m),
|
Opcode::Cdv => self.cdv(m),
|
||||||
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn adv(&self, m: &mut Machine) {
|
fn adv(&self, m: &mut Machine) {
|
||||||
@ -139,7 +129,7 @@ impl Instruction {
|
|||||||
fn bxl(&self, m: &mut Machine) {
|
fn bxl(&self, m: &mut Machine) {
|
||||||
let lhs = self.operand.value(m);
|
let lhs = self.operand.value(m);
|
||||||
let rhs = m.registers.load(Register::B);
|
let rhs = m.registers.load(Register::B);
|
||||||
m.registers.store(Register::B, lhs.bitxor(rhs));
|
m.registers.store(Register::B, lhs ^ rhs);
|
||||||
m.advance();
|
m.advance();
|
||||||
}
|
}
|
||||||
fn bst(&self, m: &mut Machine) {
|
fn bst(&self, m: &mut Machine) {
|
||||||
@ -154,9 +144,9 @@ impl Instruction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn bxc(&self, m: &mut Machine) {
|
fn bxc(&self, m: &mut Machine) {
|
||||||
let a = m.registers.load(Register::B);
|
let lhs = m.registers.load(Register::B);
|
||||||
let b = m.registers.load(Register::C);
|
let rhs = m.registers.load(Register::C);
|
||||||
m.registers.store(Register::B, a.bitxor(b));
|
m.registers.store(Register::B, lhs ^ rhs);
|
||||||
m.advance();
|
m.advance();
|
||||||
}
|
}
|
||||||
fn out(&self, m: &mut Machine) {
|
fn out(&self, m: &mut Machine) {
|
||||||
@ -189,12 +179,8 @@ pub struct Machine {
|
|||||||
impl Machine {
|
impl Machine {
|
||||||
fn run(&mut self) {
|
fn run(&mut self) {
|
||||||
let program = self.program.clone();
|
let program = self.program.clone();
|
||||||
loop {
|
while let Some(inst) = program.get(self.ip) {
|
||||||
if let Some(inst) = program.get(self.ip) {
|
|
||||||
inst.exec(self);
|
inst.exec(self);
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn advance(&mut self) {
|
fn advance(&mut self) {
|
||||||
@ -233,7 +219,7 @@ fn parse(input: &str) -> Machine {
|
|||||||
program_raw.push(operand);
|
program_raw.push(operand);
|
||||||
let opcode: Opcode = opcode.into();
|
let opcode: Opcode = opcode.into();
|
||||||
program.push(Instruction {
|
program.push(Instruction {
|
||||||
operand: opcode.interp_operand(operand as i64),
|
operand: opcode.interp_operand(operand),
|
||||||
opcode,
|
opcode,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -256,9 +242,10 @@ pub fn part1(input: &str) -> String {
|
|||||||
machine.out_file.iter().map(|n| n.to_string()).join(",")
|
machine.out_file.iter().map(|n| n.to_string()).join(",")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The program must be of the correct form to be solvable
|
||||||
pub fn solve(m: &mut Machine, guess: i64, i: usize) -> Option<i64> {
|
pub fn solve(m: &mut Machine, guess: i64, i: usize) -> Option<i64> {
|
||||||
if i as usize == m.program_raw.len() {
|
if i == m.program_raw.len() {
|
||||||
return Some(guess as i64);
|
return Some(guess);
|
||||||
}
|
}
|
||||||
let program_pos = m.program_raw.len() - 1 - i;
|
let program_pos = m.program_raw.len() - 1 - i;
|
||||||
let goal_digit = m.program_raw[program_pos];
|
let goal_digit = m.program_raw[program_pos];
|
||||||
@ -270,7 +257,7 @@ pub fn solve(m: &mut Machine, guess: i64, i: usize) -> Option<i64> {
|
|||||||
m.run();
|
m.run();
|
||||||
if m.out_file.len() == m.program_raw.len() && m.out_file[program_pos] == goal_digit {
|
if m.out_file.len() == m.program_raw.len() && m.out_file[program_pos] == goal_digit {
|
||||||
if let Some(sol) = solve(m, local_guess, i + 1) {
|
if let Some(sol) = solve(m, local_guess, i + 1) {
|
||||||
return Some(sol)
|
return Some(sol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -281,7 +268,7 @@ pub fn solve(m: &mut Machine, guess: i64, i: usize) -> Option<i64> {
|
|||||||
pub fn part2(input: &str) -> i64 {
|
pub fn part2(input: &str) -> i64 {
|
||||||
let mut machine = parse(input);
|
let mut machine = parse(input);
|
||||||
|
|
||||||
return solve(&mut machine, 0, 0).expect("expected a solution");
|
solve(&mut machine, 0, 0).expect("expected a solution")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user