296 lines
8.1 KiB
Rust
296 lines
8.1 KiB
Rust
use std::{
|
|
io::{self, Write},
|
|
env,
|
|
fs,
|
|
process,
|
|
};
|
|
|
|
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
|
|
|
#[allow(unused_macros)]
|
|
macro_rules! todo {
|
|
($($tt:tt)*) => { unimplemented!($($tt)*) };
|
|
}
|
|
|
|
fn get_input_string() -> io::Result<String> {
|
|
let args: Vec<String> = env::args()
|
|
.collect();
|
|
if args.len() <= 1 {
|
|
println!("usage: {} input.txt", args.get(0).map(String::as_str).unwrap_or("Day05"));
|
|
process::exit(1);
|
|
} else {
|
|
fs::read_to_string(&args[1])
|
|
}
|
|
}
|
|
|
|
fn main() -> Result<()> {
|
|
let program: Vec<_> = get_input_string()?
|
|
.trim()
|
|
.split(",")
|
|
.filter(|s| !s.is_empty())
|
|
.map(|n| n.parse::<isize>().unwrap())
|
|
.collect();
|
|
|
|
part1(&program);
|
|
part2(&program);
|
|
//pretty_print(&program);
|
|
Ok(())
|
|
}
|
|
|
|
/*
|
|
fn pretty_print(program: &Vec<isize>) {
|
|
let mut pc = 0;
|
|
let mut end = false;
|
|
while pc < program.len() {
|
|
let op = program[pc] % 100;
|
|
match op {
|
|
1 | 2 => {
|
|
println!("{:04} {} {} {}",
|
|
program[pc],
|
|
program[pc + 1],
|
|
program[pc + 2],
|
|
program[pc + 3]);
|
|
pc += 4;
|
|
}
|
|
3 | 4 => {
|
|
println!("{:04} {}",
|
|
program[pc],
|
|
program[pc + 1]);
|
|
pc += 2;
|
|
}
|
|
99 => {
|
|
println!("{:04}", program[pc]);
|
|
end = true;
|
|
pc += 1;
|
|
}
|
|
other => {
|
|
if end {
|
|
print!("{} ", other);
|
|
} else {
|
|
println!("{}", other);
|
|
}
|
|
pc += 1;
|
|
}
|
|
}
|
|
}
|
|
println!();
|
|
}
|
|
*/
|
|
|
|
fn part1(program: &Vec<isize>) {
|
|
println!("Running part 1 - input diagnostic code 1");
|
|
run_program(program.clone());
|
|
}
|
|
|
|
fn part2(program: &Vec<isize>) {
|
|
println!("Running part 2 - input diagnostic code 5");
|
|
run_program(program.clone());
|
|
}
|
|
|
|
fn run_program(mut program: Vec<isize>) -> Vec<isize> {
|
|
let mut pc = 0;
|
|
let mut read_count = 1;
|
|
loop {
|
|
let op = Op::from(&program[pc..]);
|
|
pc += op.len();
|
|
match op {
|
|
Op::Add { in1, in2, out, } => {
|
|
let v1 = in1.get(&program);
|
|
let v2 = in2.get(&program);
|
|
program[out] = v1 + v2;
|
|
}
|
|
Op::Mul { in1, in2, out, } => {
|
|
let v1 = in1.get(&program);
|
|
let v2 = in2.get(&program);
|
|
program[out] = v1 * v2;
|
|
}
|
|
Op::Read(pos) => {
|
|
let mut line = String::new();
|
|
let value = loop {
|
|
print!("{}> ", read_count);
|
|
io::stdout().flush().unwrap();
|
|
io::stdin().read_line(&mut line)
|
|
.expect("could not read line");
|
|
let parsed = line.trim()
|
|
.parse::<isize>();
|
|
if let Ok(value) = parsed {
|
|
break value;
|
|
}
|
|
};
|
|
read_count += 1;
|
|
program[pos] = value;
|
|
}
|
|
Op::Write(pos) => {
|
|
let value = pos.get(&program);
|
|
println!("{}", value);
|
|
}
|
|
Op::JumpTrue { test, jump } => {
|
|
let value = test.get(&program);
|
|
if value != 0 {
|
|
let addr = jump.get(&program);
|
|
assert!(addr >= 0, "invalid jump address: {}", addr);
|
|
pc = addr as usize;
|
|
}
|
|
}
|
|
Op::JumpFalse { test, jump } => {
|
|
let value = test.get(&program);
|
|
if value == 0 {
|
|
let addr = jump.get(&program);
|
|
assert!(addr >= 0, "invalid jump address: {}", addr);
|
|
pc = addr as usize;
|
|
}
|
|
}
|
|
Op::LessThan { in1, in2, out, } => {
|
|
let v1 = in1.get(&program);
|
|
let v2 = in2.get(&program);
|
|
|
|
program[out] = (v1 < v2) as isize;
|
|
}
|
|
Op::Equals { in1, in2, out, } => {
|
|
let v1 = in1.get(&program);
|
|
let v2 = in2.get(&program);
|
|
program[out] = (v1 == v2) as isize;
|
|
}
|
|
Op::Halt => {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
program
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
enum Param {
|
|
Pos(usize),
|
|
Imm(isize),
|
|
}
|
|
|
|
impl Param {
|
|
fn get(&self, program: &Vec<isize>) -> isize {
|
|
match self {
|
|
Param::Pos(p) => program[*p],
|
|
Param::Imm(v) => *v,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
enum Op {
|
|
Add {
|
|
in1: Param,
|
|
in2: Param,
|
|
out: usize,
|
|
},
|
|
Mul {
|
|
in1: Param,
|
|
in2: Param,
|
|
out: usize,
|
|
},
|
|
Read(usize),
|
|
Write(Param),
|
|
JumpTrue {
|
|
test: Param,
|
|
jump: Param,
|
|
},
|
|
JumpFalse {
|
|
test: Param,
|
|
jump: Param,
|
|
},
|
|
LessThan {
|
|
in1: Param,
|
|
in2: Param,
|
|
out: usize,
|
|
},
|
|
Equals {
|
|
in1: Param,
|
|
in2: Param,
|
|
out: usize,
|
|
},
|
|
Halt,
|
|
}
|
|
|
|
fn param_mode(op: usize, param: u32) -> usize {
|
|
let mode = op / 100;
|
|
(mode / (10usize.pow(param))) & 1
|
|
}
|
|
|
|
fn make_param(op: usize, param: u32, value: isize) -> Param {
|
|
let mode = param_mode(op, param);
|
|
match mode {
|
|
0 => {
|
|
assert!(value >= 0, "invalid position parameter for mode 0 op={} param={} value={}", op, param, value);
|
|
Param::Pos(value as usize)
|
|
},
|
|
1 => Param::Imm(value),
|
|
_ => panic!("invalid mode {} for op={} param={}", mode, op, param),
|
|
}
|
|
}
|
|
|
|
impl Op {
|
|
fn len(&self) -> usize {
|
|
match self {
|
|
Op::Add { .. } | Op::Mul { .. } | Op::LessThan { .. } | Op::Equals { .. } => 4,
|
|
Op::JumpTrue { .. } | Op::JumpFalse { .. } => 3,
|
|
Op::Read(_) | Op::Write(_) => 2,
|
|
Op::Halt => 1,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<&'_ [isize]> for Op {
|
|
fn from(other: &'_ [isize]) -> Self {
|
|
let op = other[0] as usize;
|
|
match op % 100 {
|
|
1 => {
|
|
assert!(other[3] >= 0, "invalid output parameter for op={} output={}", op, other[3]);
|
|
Op::Add {
|
|
in1: make_param(op, 0, other[1]),
|
|
in2: make_param(op, 1, other[2]),
|
|
out: other[3] as usize,
|
|
}
|
|
}
|
|
2 => {
|
|
assert!(other[3] >= 0, "invalid output parameter for op={} output={}", op, other[3]);
|
|
Op::Mul {
|
|
in1: make_param(op, 0, other[1]),
|
|
in2: make_param(op, 1, other[2]),
|
|
out: other[3] as usize,
|
|
}
|
|
}
|
|
3 => Op::Read(other[1] as usize),
|
|
4 => Op::Write(make_param(op, 0, other[1])),
|
|
5 => {
|
|
Op::JumpTrue {
|
|
test: make_param(op, 0, other[1]),
|
|
jump: make_param(op, 1, other[2]),
|
|
}
|
|
}
|
|
6 => {
|
|
Op::JumpFalse {
|
|
test: make_param(op, 0, other[1]),
|
|
jump: make_param(op, 1, other[2]),
|
|
}
|
|
}
|
|
7 => {
|
|
assert!(other[3] >= 0, "invalid output parameter for op={} output={}", op, other[3]);
|
|
Op::LessThan {
|
|
in1: make_param(op, 0, other[1]),
|
|
in2: make_param(op, 1, other[2]),
|
|
out: other[3] as usize,
|
|
}
|
|
}
|
|
8 => {
|
|
assert!(other[3] >= 0, "invalid output parameter for op={} output={}", op, other[3]);
|
|
Op::Equals {
|
|
in1: make_param(op, 0, other[1]),
|
|
in2: make_param(op, 1, other[2]),
|
|
out: other[3] as usize,
|
|
}
|
|
}
|
|
99 => Op::Halt,
|
|
op => panic!("invalid op: {}", op),
|
|
}
|
|
}
|
|
}
|