Skip to content

Instantly share code, notes, and snippets.

@jcreekmore
Created February 19, 2021 14:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jcreekmore/077c5ee47acb2323205484b02db4235b to your computer and use it in GitHub Desktop.
Save jcreekmore/077c5ee47acb2323205484b02db4235b to your computer and use it in GitHub Desktop.
Advent of Code 2018 -- Day 21
use std::str::FromStr;
use std::fmt;
use std::collections::HashSet;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Registers {
regs: Vec<usize>,
}
impl Registers {
pub fn new(zero: usize) -> Registers {
Registers { regs: vec![zero, 0, 0, 0, 0, 0] }
}
}
impl fmt::Display for Registers {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "[")?;
for i in 0..self.regs.len() {
write!(f, "{:x}", self.regs[i])?;
if i < self.regs.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "]")
}
}
#[derive(Debug)]
pub struct Inst {
op: Opcode,
a: usize,
b: usize,
c: usize,
}
impl FromStr for Inst {
type Err = String;
fn from_str(s: &str) -> Result<Inst, String> {
let cap: Vec<&str> = s.trim().split(' ').collect();
Ok(Inst {
op: cap[0].into(),
a: cap[1].parse::<usize>().unwrap(),
b: cap[2].parse::<usize>().unwrap(),
c: cap[3].parse::<usize>().unwrap(),
})
}
}
impl fmt::Display for Inst {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{} {:x} {:x} {:x}", self.op, self.a, self.b, self.c)
}
}
fn addr(inst: &Inst, input: &Registers) -> Registers {
let mut out = input.clone();
out.regs[inst.c] = input.regs[inst.a] + input.regs[inst.b];
out
}
fn addi(inst: &Inst, input: &Registers) -> Registers {
let mut out = input.clone();
out.regs[inst.c] = input.regs[inst.a] + inst.b;
out
}
fn mulr(inst: &Inst, input: &Registers) -> Registers {
let mut out = input.clone();
out.regs[inst.c] = input.regs[inst.a] * input.regs[inst.b];
out
}
fn muli(inst: &Inst, input: &Registers) -> Registers {
let mut out = input.clone();
out.regs[inst.c] = input.regs[inst.a] * inst.b;
out
}
fn banr(inst: &Inst, input: &Registers) -> Registers {
let mut out = input.clone();
out.regs[inst.c] = input.regs[inst.a] & input.regs[inst.b];
out
}
fn bani(inst: &Inst, input: &Registers) -> Registers {
let mut out = input.clone();
out.regs[inst.c] = input.regs[inst.a] & inst.b;
out
}
fn borr(inst: &Inst, input: &Registers) -> Registers {
let mut out = input.clone();
out.regs[inst.c] = input.regs[inst.a] | input.regs[inst.b];
out
}
fn bori(inst: &Inst, input: &Registers) -> Registers {
let mut out = input.clone();
out.regs[inst.c] = input.regs[inst.a] | inst.b;
out
}
fn setr(inst: &Inst, input: &Registers) -> Registers {
let mut out = input.clone();
out.regs[inst.c] = input.regs[inst.a];
out
}
fn seti(inst: &Inst, input: &Registers) -> Registers {
let mut out = input.clone();
out.regs[inst.c] = inst.a;
out
}
fn gtir(inst: &Inst, input: &Registers) -> Registers {
let mut out = input.clone();
out.regs[inst.c] = if inst.a > input.regs[inst.b] { 1 } else { 0 };
out
}
fn gtri(inst: &Inst, input: &Registers) -> Registers {
let mut out = input.clone();
out.regs[inst.c] = if input.regs[inst.a] > inst.b { 1 } else { 0 };
out
}
fn gtrr(inst: &Inst, input: &Registers) -> Registers {
let mut out = input.clone();
out.regs[inst.c] = if input.regs[inst.a] > input.regs[inst.b] { 1 } else { 0 };
out
}
fn eqir(inst: &Inst, input: &Registers) -> Registers {
let mut out = input.clone();
out.regs[inst.c] = if inst.a == input.regs[inst.b] { 1 } else { 0 };
out
}
fn eqri(inst: &Inst, input: &Registers) -> Registers {
let mut out = input.clone();
out.regs[inst.c] = if input.regs[inst.a] == inst.b { 1 } else { 0 };
out
}
fn eqrr(inst: &Inst, input: &Registers) -> Registers {
let mut out = input.clone();
out.regs[inst.c] = if input.regs[inst.a] == input.regs[inst.b] { 1 } else { 0 };
out
}
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum Opcode {
Addr,
Addi,
Mulr,
Muli,
Banr,
Bani,
Borr,
Bori,
Setr,
Seti,
Gtir,
Gtri,
Gtrr,
Eqir,
Eqri,
Eqrr,
}
impl fmt::Display for Opcode {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let s = match *self {
Opcode::Addr => "addr",
Opcode::Addi => "addi",
Opcode::Mulr => "mulr",
Opcode::Muli => "muli",
Opcode::Banr => "banr",
Opcode::Bani => "bani",
Opcode::Borr => "borr",
Opcode::Bori => "bori",
Opcode::Setr => "setr",
Opcode::Seti => "seti",
Opcode::Gtir => "gtir",
Opcode::Gtri => "gtri",
Opcode::Gtrr => "gtrr",
Opcode::Eqir => "eqir",
Opcode::Eqri => "eqri",
Opcode::Eqrr => "eqrr",
};
write!(f, "{}", s)
}
}
impl From<&str> for Opcode {
fn from(s: &str) -> Opcode {
match s {
"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,
_ => unreachable!(),
}
}
}
impl Opcode {
pub fn call(&self, inst: &Inst, before: &Registers) -> Registers {
match *self {
Opcode::Addr => addr(inst, before),
Opcode::Addi => addi(inst, before),
Opcode::Mulr => mulr(inst, before),
Opcode::Muli => muli(inst, before),
Opcode::Banr => banr(inst, before),
Opcode::Bani => bani(inst, before),
Opcode::Borr => borr(inst, before),
Opcode::Bori => bori(inst, before),
Opcode::Setr => setr(inst, before),
Opcode::Seti => seti(inst, before),
Opcode::Gtir => gtir(inst, before),
Opcode::Gtri => gtri(inst, before),
Opcode::Gtrr => gtrr(inst, before),
Opcode::Eqir => eqir(inst, before),
Opcode::Eqri => eqri(inst, before),
Opcode::Eqrr => eqrr(inst, before),
}
}
}
#[derive(Debug)]
pub struct Cpu {
ip: usize,
ip_reg: usize,
pub regs: Registers,
mem: Vec<Inst>,
}
impl Cpu {
pub fn new(input: &str, zero: usize) -> Cpu {
let lines = input.lines().map(|s| s.trim()).collect::<Vec<&str>>();
let ip_reg = lines[0].split(' ').collect::<Vec<&str>>()[1].parse::<usize>().unwrap();
let mem = lines[1..].into_iter().map(|s| s.parse::<Inst>().unwrap()).collect::<Vec<Inst>>();
Cpu {
ip: 0,
ip_reg,
regs: Registers::new(zero),
mem
}
}
pub fn run(&mut self) -> usize {
let mut hit = HashSet::new();
let mut last = 0;
let mut count = 0;
loop {
if self.ip >= self.mem.len() {
break;
}
self.regs.regs[self.ip_reg] = self.ip;
let inst = &self.mem[self.ip];
let out = inst.op.call(inst, &self.regs);
if self.ip == 28 {
//println!("ip={} {} {}", self.ip, inst, out);
if !hit.insert(out.regs[5]) {
println!("last = {}", last);
break;
}
last = out.regs[5];
}
self.regs = out;
self.ip = self.regs.regs[self.ip_reg];
self.ip += 1;
count += 1;
}
count
}
}
#[cfg(test)]
mod tests {
use super::*;
const INPUT: &'static str = include_str!("input");
#[test]
fn it_works() {
let mut input = Cpu::new(INPUT, 0);
println!("inst count: {}", input.run());
}
}
#ip 2
seti 123 0 5
bani 5 456 5
eqri 5 72 5
addr 5 2 2
seti 0 0 2
seti 0 9 5
bori 5 65536 3
seti 7586220 4 5
bani 3 255 1
addr 5 1 5
bani 5 16777215 5
muli 5 65899 5
bani 5 16777215 5
gtir 256 3 1
addr 1 2 2
addi 2 1 2
seti 27 9 2
seti 0 9 1
addi 1 1 4
muli 4 256 4
gtrr 4 3 4
addr 4 2 2
addi 2 1 2
seti 25 4 2
addi 1 1 1
seti 17 2 2
setr 1 6 3
seti 7 8 2
eqrr 5 0 1
addr 1 2 2
seti 5 0 2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment