295
day05/Day05.rs
Normal file
295
day05/Day05.rs
Normal file
@@ -0,0 +1,295 @@
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user