mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
Implement day 19.
With nice hotspot optimization for part 2.
This commit is contained in:
37
2018/inputs/19.txt
Normal file
37
2018/inputs/19.txt
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#ip 3
|
||||||
|
addi 3 16 3
|
||||||
|
seti 1 8 1
|
||||||
|
seti 1 3 4
|
||||||
|
mulr 1 4 2
|
||||||
|
eqrr 2 5 2
|
||||||
|
addr 2 3 3
|
||||||
|
addi 3 1 3
|
||||||
|
addr 1 0 0
|
||||||
|
addi 4 1 4
|
||||||
|
gtrr 4 5 2
|
||||||
|
addr 3 2 3
|
||||||
|
seti 2 6 3
|
||||||
|
addi 1 1 1
|
||||||
|
gtrr 1 5 2
|
||||||
|
addr 2 3 3
|
||||||
|
seti 1 5 3
|
||||||
|
mulr 3 3 3
|
||||||
|
addi 5 2 5
|
||||||
|
mulr 5 5 5
|
||||||
|
mulr 3 5 5
|
||||||
|
muli 5 11 5
|
||||||
|
addi 2 5 2
|
||||||
|
mulr 2 3 2
|
||||||
|
addi 2 21 2
|
||||||
|
addr 5 2 5
|
||||||
|
addr 3 0 3
|
||||||
|
seti 0 4 3
|
||||||
|
setr 3 1 2
|
||||||
|
mulr 2 3 2
|
||||||
|
addr 3 2 2
|
||||||
|
mulr 3 2 2
|
||||||
|
muli 2 14 2
|
||||||
|
mulr 2 3 2
|
||||||
|
addr 5 2 5
|
||||||
|
seti 0 3 0
|
||||||
|
seti 0 6 3
|
||||||
@@ -1,25 +1,218 @@
|
|||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
use common::Solution;
|
use common::Solution;
|
||||||
|
use std::io::BufReader;
|
||||||
|
use std::io::BufRead;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||||
|
enum OpCode {
|
||||||
|
ADDR,
|
||||||
|
ADDI,
|
||||||
|
MULR,
|
||||||
|
MULI,
|
||||||
|
BANR,
|
||||||
|
BANI,
|
||||||
|
BORR,
|
||||||
|
BORI,
|
||||||
|
SETR,
|
||||||
|
SETI,
|
||||||
|
GTIR,
|
||||||
|
GTRI,
|
||||||
|
GTRR,
|
||||||
|
EQIR,
|
||||||
|
EQRI,
|
||||||
|
EQRR,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OpCode {
|
||||||
|
fn valid(self, op: &[i32; 4], before: &[i32; 4], after: &[i32; 4]) -> bool {
|
||||||
|
let mut cpu = CPU::new();
|
||||||
|
|
||||||
|
cpu.registers.copy_from_slice(before);
|
||||||
|
if let Ok(val) = cpu.execute(self, &op[1..4]) {
|
||||||
|
if val == after[op[3] as usize] {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for OpCode {
|
||||||
|
fn from(name: &str) -> Self {
|
||||||
|
match name {
|
||||||
|
"addr" => OpCode::ADDR,
|
||||||
|
"addi" => OpCode::ADDI,
|
||||||
|
"mulr" => OpCode::MULR,
|
||||||
|
"muli" => OpCode::MULI,
|
||||||
|
"banr" => OpCode::BANR,
|
||||||
|
"bani" => OpCode::BANI,
|
||||||
|
"borr" => OpCode::BORR,
|
||||||
|
"bori" => OpCode::BORI,
|
||||||
|
"setr" => OpCode::SETR,
|
||||||
|
"seti" => OpCode::SETI,
|
||||||
|
"gtir" => OpCode::GTIR,
|
||||||
|
"gtri" => OpCode::GTRI,
|
||||||
|
"gtrr" => OpCode::GTRR,
|
||||||
|
"eqir" => OpCode::EQIR,
|
||||||
|
"eqri" => OpCode::EQRI,
|
||||||
|
"eqrr" => OpCode::EQRR,
|
||||||
|
_ => panic!("Invalid opcode {}", name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const OP_LIST: [OpCode; 16] = [
|
||||||
|
OpCode::ADDR,
|
||||||
|
OpCode::ADDI,
|
||||||
|
OpCode::MULR,
|
||||||
|
OpCode::MULI,
|
||||||
|
OpCode::BANR,
|
||||||
|
OpCode::BANI,
|
||||||
|
OpCode::BORR,
|
||||||
|
OpCode::BORI,
|
||||||
|
OpCode::SETR,
|
||||||
|
OpCode::SETI,
|
||||||
|
OpCode::GTIR,
|
||||||
|
OpCode::GTRI,
|
||||||
|
OpCode::GTRR,
|
||||||
|
OpCode::EQIR,
|
||||||
|
OpCode::EQRI,
|
||||||
|
OpCode::EQRR,
|
||||||
|
];
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum CPUErr {
|
||||||
|
InvalidRegister(i32),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Day19 {}
|
struct CPU {
|
||||||
|
registers: [i32; 6],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CPU {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
pub fn execute(&mut self, op: OpCode, var: &[i32]) -> Result<i32, CPUErr> {
|
||||||
|
use self::OpCode::*;
|
||||||
|
let res = match op {
|
||||||
|
ADDR => self.reg(var[0])? + self.reg(var[1])?,
|
||||||
|
ADDI => self.reg(var[0])? + var[1],
|
||||||
|
MULR => self.reg(var[0])? * self.reg(var[1])?,
|
||||||
|
MULI => self.reg(var[0])? * var[1],
|
||||||
|
BANR => self.reg(var[0])? & self.reg(var[1])?,
|
||||||
|
BANI => self.reg(var[0])? & var[1],
|
||||||
|
BORR => self.reg(var[0])? | self.reg(var[1])?,
|
||||||
|
BORI => self.reg(var[0])? | var[1],
|
||||||
|
SETR => self.reg(var[0])?,
|
||||||
|
SETI => var[0],
|
||||||
|
GTRR => (self.reg(var[0])? > self.reg(var[1])?).into(),
|
||||||
|
GTIR => (var[0] > self.reg(var[1])?).into(),
|
||||||
|
GTRI => (self.reg(var[0])? > var[1]).into(),
|
||||||
|
EQRR => (self.reg(var[0])? == self.reg(var[1])?).into(),
|
||||||
|
EQIR => (var[0] == self.reg(var[1])?).into(),
|
||||||
|
EQRI => (self.reg(var[0])? == var[1]).into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.registers[var[2] as usize] = res;
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reg(&self, index: i32) -> Result<i32, CPUErr> {
|
||||||
|
if let Some(val) = self.registers.get(index as usize) {
|
||||||
|
Ok(*val)
|
||||||
|
} else {
|
||||||
|
Err(CPUErr::InvalidRegister(index))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Day19 {
|
||||||
|
program: Vec<(OpCode, [i32; 3])>,
|
||||||
|
ip: usize,
|
||||||
|
}
|
||||||
|
|
||||||
impl Day19 {
|
impl Day19 {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_input(&mut self, input: &mut Read) {
|
||||||
|
let reader = BufReader::new(input);
|
||||||
|
|
||||||
|
for line in reader.lines() {
|
||||||
|
let line = line.unwrap();
|
||||||
|
if line.chars().next().unwrap() == '#' {
|
||||||
|
self.ip = line.split(' ').last().unwrap().parse().unwrap();
|
||||||
|
} else {
|
||||||
|
let mut parts = line.split(' ');
|
||||||
|
let opcode = OpCode::from(parts.next().unwrap());
|
||||||
|
let mut operands = [0; 3];
|
||||||
|
for i in 0..3 {
|
||||||
|
operands[i] = parts.next().unwrap().parse().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.program.push((opcode, operands));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Solution for Day19 {
|
impl Solution for Day19 {
|
||||||
fn part1(&mut self, _input: &mut Read) -> String {
|
fn part1(&mut self, input: &mut Read) -> String {
|
||||||
unimplemented!()
|
self.read_input(input);
|
||||||
|
|
||||||
|
let mut cpu = CPU::new();
|
||||||
|
|
||||||
|
while (cpu.registers[self.ip] as usize) < self.program.len() {
|
||||||
|
let (opcode, operands) = &self.program[cpu.registers[self.ip] as usize];
|
||||||
|
cpu.execute(*opcode, operands);
|
||||||
|
cpu.registers[self.ip] += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
format!("{}", cpu.registers[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part2(&mut self, _input: &mut Read) -> String {
|
fn part2(&mut self, input: &mut Read) -> String {
|
||||||
unimplemented!()
|
self.read_input(input);
|
||||||
|
|
||||||
|
let mut cpu = CPU::new();
|
||||||
|
cpu.registers[0] = 1;
|
||||||
|
|
||||||
|
// This is optimized for my input.
|
||||||
|
assert_eq!(self.ip, 3);
|
||||||
|
|
||||||
|
while (cpu.registers[3] as usize) < self.program.len() {
|
||||||
|
if cpu.registers[3] == 3 {
|
||||||
|
let reg = &mut cpu.registers;
|
||||||
|
if reg[5] % reg[1] == 0 {
|
||||||
|
reg[0] += reg[1];
|
||||||
|
}
|
||||||
|
reg[3] = 12;
|
||||||
|
}
|
||||||
|
let (opcode, operands) = &self.program[cpu.registers[self.ip] as usize];
|
||||||
|
cpu.execute(*opcode, operands);
|
||||||
|
cpu.registers[self.ip] += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
format!("{}", cpu.registers[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {}
|
mod tests {
|
||||||
|
use day19::Day19;
|
||||||
|
use common::Solution;
|
||||||
|
|
||||||
|
const SAMPLE_INPUT: &[u8] = include_bytes!("samples/19.txt");
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_part1() {
|
||||||
|
let mut instance = Day19::new();
|
||||||
|
assert_eq!("6", instance.part1(&mut SAMPLE_INPUT));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
8
2018/src/samples/19.txt
Normal file
8
2018/src/samples/19.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ip 0
|
||||||
|
seti 5 0 1
|
||||||
|
seti 6 0 2
|
||||||
|
addi 0 1 0
|
||||||
|
addr 1 2 3
|
||||||
|
setr 1 0 0
|
||||||
|
seti 8 0 4
|
||||||
|
seti 9 0 5
|
||||||
Reference in New Issue
Block a user