mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
Clean up day 16 and 19.
Day 16 and 19 share the same CPU and now they actually share the same code for it.
This commit is contained in:
167
2018/src/cpu.rs
Normal file
167
2018/src/cpu.rs
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
//! Shared CPU module
|
||||||
|
//!
|
||||||
|
//! Day 16 and day 19 use the same CPU, so that code is shared (and documented) here.
|
||||||
|
|
||||||
|
/// Representation an OpCode for the AoC 2018 CPU.
|
||||||
|
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||||
|
pub enum OpCode {
|
||||||
|
ADDR,
|
||||||
|
ADDI,
|
||||||
|
MULR,
|
||||||
|
MULI,
|
||||||
|
BANR,
|
||||||
|
BANI,
|
||||||
|
BORR,
|
||||||
|
BORI,
|
||||||
|
SETR,
|
||||||
|
SETI,
|
||||||
|
GTIR,
|
||||||
|
GTRI,
|
||||||
|
GTRR,
|
||||||
|
EQIR,
|
||||||
|
EQRI,
|
||||||
|
EQRR,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OpCode {
|
||||||
|
/// Check if the given before/after state is valid for a particular OpCode.
|
||||||
|
///
|
||||||
|
/// For this, a possible op is represented as an array of integers, where the first
|
||||||
|
/// integer (the possible op-code) is ignored.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use aoc_2018::cpu::OpCode;
|
||||||
|
///
|
||||||
|
/// assert_eq!(true, OpCode::ADDI.is_valid(&[0, 0, 3, 0], &[0; 6], &[3, 0, 0, 0, 0, 0]))
|
||||||
|
/// ```
|
||||||
|
pub fn is_valid(self, op: &[i32; 4], before: &[i32; 6], after: &[i32; 6]) -> 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
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterator over all possible OpCode values.
|
||||||
|
///
|
||||||
|
/// This iterator is backed internally by a static array of all op codes.
|
||||||
|
pub fn values() -> impl Iterator<Item=Self> {
|
||||||
|
OP_LIST.iter().cloned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
];
|
||||||
|
|
||||||
|
/// CPU Error
|
||||||
|
///
|
||||||
|
/// This can be returned as an error when the CPU cannot execute
|
||||||
|
/// an instruction.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum CPUErr {
|
||||||
|
/// An invalid register was requested, with this register number.
|
||||||
|
InvalidRegister(i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct CPU {
|
||||||
|
/// Internal register state. Can be modified freely.
|
||||||
|
pub registers: [i32; 6],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CPU {
|
||||||
|
/// Construct a new CPU instance.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute an OpCode on the CPU
|
||||||
|
///
|
||||||
|
/// This method will return the result of the operation executed, or a
|
||||||
|
/// CPUErr when execution fails.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// This function does not check bounds on the operands slice (var) and the output register.
|
||||||
|
/// Thus, when the operands slice has less than 3 elements or the target register does not
|
||||||
|
/// exist, this function will panic.
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,105 +6,8 @@ use std::io::Read;
|
|||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
use common::Solution;
|
use common::Solution;
|
||||||
|
use cpu::OpCode;
|
||||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
use cpu::CPU;
|
||||||
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 = Default::default();
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)]
|
|
||||||
struct CPU {
|
|
||||||
registers: [i32; 4],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CPU {
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Day16 {
|
pub struct Day16 {
|
||||||
matcher: Regex,
|
matcher: Regex,
|
||||||
@@ -119,15 +22,15 @@ impl Day16 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read(&mut self, reader: &mut BufRead, target: &mut [i32; 4]) -> bool {
|
fn read(&mut self, reader: &mut BufRead, target: &mut [i32]) -> bool {
|
||||||
self.buf.clear();
|
self.buf.clear();
|
||||||
if reader.read_line(&mut self.buf).is_err() {
|
if reader.read_line(&mut self.buf).is_err() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(captures) = self.matcher.captures(&self.buf) {
|
if let Some(captures) = self.matcher.captures(&self.buf) {
|
||||||
for i in 0..4 {
|
for (target, cap) in target.iter_mut().zip(captures.iter().skip(1)) {
|
||||||
target[i] = captures[i + 1].parse().unwrap();
|
*target = cap.unwrap().as_str().parse().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
@@ -143,22 +46,21 @@ impl Day16 {
|
|||||||
HashSet::new(), HashSet::new(), HashSet::new(), HashSet::new(),
|
HashSet::new(), HashSet::new(), HashSet::new(), HashSet::new(),
|
||||||
HashSet::new(), HashSet::new(), HashSet::new(), HashSet::new(),
|
HashSet::new(), HashSet::new(), HashSet::new(), HashSet::new(),
|
||||||
];
|
];
|
||||||
let mut before = [0; 4];
|
let mut before = [0; 6];
|
||||||
let mut op = [0; 4];
|
let mut op = [0; 4];
|
||||||
let mut after = [0; 4];
|
let mut after = [0; 6];
|
||||||
while self.read(&mut reader, &mut before) {
|
while self.read(&mut reader, &mut before[..4]) {
|
||||||
self.read(&mut reader, &mut op);
|
self.read(&mut reader, &mut op);
|
||||||
self.read(&mut reader, &mut after);
|
self.read(&mut reader, &mut after[..4]);
|
||||||
reader.read_line(&mut self.buf).unwrap_or(0);
|
reader.read_line(&mut self.buf).unwrap_or(0);
|
||||||
|
|
||||||
if mappings[op[0] as usize].is_empty() {
|
if mappings[op[0] as usize].is_empty() {
|
||||||
mappings[op[0] as usize].extend(OP_LIST.iter()
|
mappings[op[0] as usize].extend(OpCode::values()
|
||||||
.filter(|x| x.valid(&op, &before, &after))
|
.filter(|x| x.is_valid(&op, &before, &after)));
|
||||||
.cloned());
|
|
||||||
} else {
|
} else {
|
||||||
for option in OP_LIST.iter()
|
for option in OpCode::values()
|
||||||
.filter(|x| !x.valid(&op, &before, &after)) {
|
.filter(|x| !x.is_valid(&op, &before, &after)) {
|
||||||
mappings[op[0] as usize].remove(option);
|
mappings[op[0] as usize].remove(&option);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -207,18 +109,18 @@ impl Solution for Day16 {
|
|||||||
fn part1(&mut self, input: &mut Read) -> String {
|
fn part1(&mut self, input: &mut Read) -> String {
|
||||||
let mut reader = BufReader::new(input);
|
let mut reader = BufReader::new(input);
|
||||||
|
|
||||||
let mut before = [0; 4];
|
let mut before = [0; 6];
|
||||||
let mut op = [0; 4];
|
let mut op = [0; 4];
|
||||||
let mut after = [0; 4];
|
let mut after = [0; 6];
|
||||||
let mut counter = 0;
|
let mut counter = 0;
|
||||||
|
|
||||||
while self.read(&mut reader, &mut before) {
|
while self.read(&mut reader, &mut before[..4]) {
|
||||||
self.read(&mut reader, &mut op);
|
self.read(&mut reader, &mut op);
|
||||||
self.read(&mut reader, &mut after);
|
self.read(&mut reader, &mut after[..4]);
|
||||||
reader.read_line(&mut self.buf).unwrap_or(0);
|
reader.read_line(&mut self.buf).unwrap_or(0);
|
||||||
|
|
||||||
let valid = OP_LIST.iter()
|
let valid = OpCode::values()
|
||||||
.filter(|x| x.valid(&op, &before, &after))
|
.filter(|x| x.is_valid(&op, &before, &after))
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
if valid >= 3 {
|
if valid >= 3 {
|
||||||
@@ -238,7 +140,7 @@ impl Solution for Day16 {
|
|||||||
// Skip a line
|
// Skip a line
|
||||||
reader.read_line(&mut self.buf).unwrap();
|
reader.read_line(&mut self.buf).unwrap();
|
||||||
|
|
||||||
let mut cpu: CPU = Default::default();
|
let mut cpu = CPU::new();
|
||||||
|
|
||||||
while self.read(&mut reader, &mut op) {
|
while self.read(&mut reader, &mut op) {
|
||||||
cpu.execute(mapping[op[0] as usize], &op[1..4]).unwrap();
|
cpu.execute(mapping[op[0] as usize], &op[1..4]).unwrap();
|
||||||
|
|||||||
@@ -1,134 +1,10 @@
|
|||||||
|
use std::io::BufRead;
|
||||||
|
use std::io::BufReader;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
use common::Solution;
|
use common::Solution;
|
||||||
use std::io::BufReader;
|
use cpu::CPU;
|
||||||
use std::io::BufRead;
|
use cpu::OpCode;
|
||||||
|
|
||||||
#[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)]
|
|
||||||
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)]
|
#[derive(Default)]
|
||||||
pub struct Day19 {
|
pub struct Day19 {
|
||||||
@@ -170,7 +46,7 @@ impl Solution for Day19 {
|
|||||||
|
|
||||||
while (cpu.registers[self.ip] as usize) < self.program.len() {
|
while (cpu.registers[self.ip] as usize) < self.program.len() {
|
||||||
let (opcode, operands) = &self.program[cpu.registers[self.ip] as usize];
|
let (opcode, operands) = &self.program[cpu.registers[self.ip] as usize];
|
||||||
cpu.execute(*opcode, operands);
|
cpu.execute(*opcode, operands).unwrap();
|
||||||
cpu.registers[self.ip] += 1;
|
cpu.registers[self.ip] += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +71,7 @@ impl Solution for Day19 {
|
|||||||
reg[3] = 12;
|
reg[3] = 12;
|
||||||
}
|
}
|
||||||
let (opcode, operands) = &self.program[cpu.registers[self.ip] as usize];
|
let (opcode, operands) = &self.program[cpu.registers[self.ip] as usize];
|
||||||
cpu.execute(*opcode, operands);
|
cpu.execute(*opcode, operands).unwrap();
|
||||||
cpu.registers[self.ip] += 1;
|
cpu.registers[self.ip] += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,14 +81,14 @@ impl Solution for Day19 {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use day19::Day19;
|
|
||||||
use common::Solution;
|
use common::Solution;
|
||||||
|
use day19::Day19;
|
||||||
|
|
||||||
const SAMPLE_INPUT: &[u8] = include_bytes!("samples/19.txt");
|
const SAMPLE_INPUT: &[u8] = include_bytes!("samples/19.txt");
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sample_part1() {
|
fn sample_part1() {
|
||||||
let mut instance = Day19::new();
|
let mut instance = Day19::new();
|
||||||
assert_eq!("6", instance.part1(&mut SAMPLE_INPUT));
|
assert_eq!("7", instance.part1(&mut SAMPLE_INPUT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ extern crate itertools;
|
|||||||
extern crate regex;
|
extern crate regex;
|
||||||
|
|
||||||
pub mod common;
|
pub mod common;
|
||||||
|
pub mod cpu;
|
||||||
pub mod day01;
|
pub mod day01;
|
||||||
pub mod day02;
|
pub mod day02;
|
||||||
pub mod day03;
|
pub mod day03;
|
||||||
|
|||||||
Reference in New Issue
Block a user