parent
fb264f5cd7
commit
039d772758
@ -0,0 +1,201 @@
|
|||||||
|
use std::error::Error;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
use advent_of_code::main;
|
||||||
|
|
||||||
|
main!();
|
||||||
|
|
||||||
|
fn solve(input: &str) -> Result<String, Box<Error>> {
|
||||||
|
let mut program: Program = input.parse()?;
|
||||||
|
program.registers[0] = 1;
|
||||||
|
let registers = program.last().unwrap();
|
||||||
|
let output = registers[0].to_string();
|
||||||
|
Ok(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Registers = [usize; 6];
|
||||||
|
|
||||||
|
struct Program {
|
||||||
|
ip: usize,
|
||||||
|
instructions: Vec<Instruction>,
|
||||||
|
registers: Registers,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Program {
|
||||||
|
fn execute(&mut self, i: &Instruction) {
|
||||||
|
match i.opcode {
|
||||||
|
Opcode::Addr => self.registers[i.c] = self.registers[i.a] + self.registers[i.b],
|
||||||
|
Opcode::Addi => self.registers[i.c] = self.registers[i.a] + i.b,
|
||||||
|
Opcode::Mulr => self.registers[i.c] = self.registers[i.a] * self.registers[i.b],
|
||||||
|
Opcode::Muli => self.registers[i.c] = self.registers[i.a] * i.b,
|
||||||
|
Opcode::Banr => self.registers[i.c] = self.registers[i.a] & self.registers[i.b],
|
||||||
|
Opcode::Bani => self.registers[i.c] = self.registers[i.a] & i.b,
|
||||||
|
Opcode::Borr => self.registers[i.c] = self.registers[i.a] | self.registers[i.b],
|
||||||
|
Opcode::Bori => self.registers[i.c] = self.registers[i.a] | i.b,
|
||||||
|
Opcode::Setr => self.registers[i.c] = self.registers[i.a],
|
||||||
|
Opcode::Seti => self.registers[i.c] = i.a,
|
||||||
|
Opcode::Gtir => self.registers[i.c] = if i.a > self.registers[i.b] { 1 } else { 0 },
|
||||||
|
Opcode::Gtri => self.registers[i.c] = if self.registers[i.a] > i.b { 1 } else { 0 },
|
||||||
|
Opcode::Gtrr => {
|
||||||
|
self.registers[i.c] = if self.registers[i.a] > self.registers[i.b] {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Opcode::Eqir => self.registers[i.c] = if i.a == self.registers[i.b] { 1 } else { 0 },
|
||||||
|
Opcode::Eqri => self.registers[i.c] = if self.registers[i.a] == i.b { 1 } else { 0 },
|
||||||
|
Opcode::Eqrr => {
|
||||||
|
self.registers[i.c] = if self.registers[i.a] == self.registers[i.b] {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for Program {
|
||||||
|
type Item = Registers;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let ins = *self.instructions.get(self.registers[self.ip])?;
|
||||||
|
self.execute(&ins);
|
||||||
|
self.registers[self.ip] += 1;
|
||||||
|
Some(self.registers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_program() {
|
||||||
|
let mut program: Program = r"
|
||||||
|
#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
|
||||||
|
"
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(program.next().unwrap(), [1, 5, 0, 0, 0, 0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct Instruction {
|
||||||
|
opcode: Opcode,
|
||||||
|
a: usize,
|
||||||
|
b: usize,
|
||||||
|
c: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum Opcode {
|
||||||
|
Addr,
|
||||||
|
Addi,
|
||||||
|
Mulr,
|
||||||
|
Muli,
|
||||||
|
Banr,
|
||||||
|
Bani,
|
||||||
|
Borr,
|
||||||
|
Bori,
|
||||||
|
Setr,
|
||||||
|
Seti,
|
||||||
|
Gtir,
|
||||||
|
Gtri,
|
||||||
|
Gtrr,
|
||||||
|
Eqir,
|
||||||
|
Eqri,
|
||||||
|
Eqrr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Program {
|
||||||
|
type Err = Box<Error>;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let mut lines = s.trim().lines();
|
||||||
|
let ip_re = Regex::new(r"^#ip (\d+)$").unwrap();
|
||||||
|
let ip = lines
|
||||||
|
.next()
|
||||||
|
.and_then(|l| ip_re.captures(l))
|
||||||
|
.and_then(|c| c.get(1))
|
||||||
|
.unwrap()
|
||||||
|
.as_str()
|
||||||
|
.parse()?;
|
||||||
|
|
||||||
|
let instructions = lines.map(|l| l.parse()).collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
|
let registers = [0; 6];
|
||||||
|
|
||||||
|
Ok(Program {
|
||||||
|
ip,
|
||||||
|
instructions,
|
||||||
|
registers,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Instruction {
|
||||||
|
type Err = Box<Error>;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let mut s = s.split_whitespace();
|
||||||
|
let opcode = s.next().unwrap().parse()?;
|
||||||
|
let a = s.next().unwrap().parse()?;
|
||||||
|
let b = s.next().unwrap().parse()?;
|
||||||
|
let c = s.next().unwrap().parse()?;
|
||||||
|
Ok(Instruction { opcode, a, b, c })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Opcode {
|
||||||
|
type Err = Box<Error>;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let 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!(),
|
||||||
|
};
|
||||||
|
Ok(opcode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OPCODES = {
|
||||||
|
// addr: ->(a, b, c) { ->(registers) { registers[c] = registers[a] + registers[b] } },
|
||||||
|
// addi: ->(a, b, c) { ->(registers) { registers[c] = registers[a] + b } },
|
||||||
|
// mulr: ->(a, b, c) { ->(registers) { registers[c] = registers[a] * registers[b] } },
|
||||||
|
// muli: ->(a, b, c) { ->(registers) { registers[c] = registers[a] * b } },
|
||||||
|
// banr: ->(a, b, c) { ->(registers) { registers[c] = registers[a] & registers[b] } },
|
||||||
|
// bani: ->(a, b, c) { ->(registers) { registers[c] = registers[a] & b } },
|
||||||
|
// borr: ->(a, b, c) { ->(registers) { registers[c] = registers[a] | registers[b] } },
|
||||||
|
// bori: ->(a, b, c) { ->(registers) { registers[c] = registers[a] | b } },
|
||||||
|
// setr: ->(a, b, c) { ->(registers) { registers[c] = registers[a] } },
|
||||||
|
// seti: ->(a, b, c) { ->(registers) { registers[c] = a } },
|
||||||
|
// gtir: ->(a, b, c) { ->(registers) { registers[c] = (a > registers[b]) ? 1 : 0 } },
|
||||||
|
// gtri: ->(a, b, c) { ->(registers) { registers[c] = (registers[a] > b) ? 1 : 0 } },
|
||||||
|
// gtrr: ->(a, b, c) { ->(registers) { registers[c] = (registers[a] > registers[b]) ? 1 : 0 } },
|
||||||
|
// eqir: ->(a, b, c) { ->(registers) { registers[c] = (a == registers[b]) ? 1 : 0 } },
|
||||||
|
// eqri: ->(a, b, c) { ->(registers) { registers[c] = (registers[a] == b) ? 1 : 0 } },
|
||||||
|
// eqrr: ->(a, b, c) { ->(registers) { registers[c] = (registers[a] == registers[b]) ? 1 : 0 } },
|
||||||
|
// }
|
Loading…
Reference in new issue