Day 9 part 1

This commit is contained in:
Wesley Moore 2019-12-09 16:54:32 +11:00
parent 52fe8eb76f
commit 9a7817e6ff
No known key found for this signature in database
GPG key ID: BF67766C0BC2D0EE
5 changed files with 137 additions and 51 deletions

1
2019/input/day9.txt Normal file
View file

@ -0,0 +1 @@
1102,34463338,34463338,63,1007,63,34463338,63,1005,63,53,1102,1,3,1000,109,988,209,12,9,1000,209,6,209,3,203,0,1008,1000,1,63,1005,63,65,1008,1000,2,63,1005,63,904,1008,1000,0,63,1005,63,58,4,25,104,0,99,4,0,104,0,99,4,17,104,0,99,0,0,1101,39,0,1004,1101,0,37,1013,1101,0,28,1001,1101,0,38,1005,1101,23,0,1008,1102,1,0,1020,1102,1,26,1010,1102,31,1,1009,1101,29,0,1015,1102,459,1,1024,1101,33,0,1007,1101,0,30,1016,1101,32,0,1002,1102,1,494,1027,1101,0,216,1029,1101,497,0,1026,1101,0,303,1022,1102,1,21,1018,1102,1,36,1006,1102,1,27,1014,1102,296,1,1023,1102,454,1,1025,1102,35,1,1003,1101,22,0,1017,1102,225,1,1028,1102,1,20,1011,1101,1,0,1021,1101,0,24,1000,1101,0,25,1019,1101,0,34,1012,109,13,21102,40,1,0,1008,1013,40,63,1005,63,203,4,187,1106,0,207,1001,64,1,64,1002,64,2,64,109,5,2106,0,10,4,213,1001,64,1,64,1105,1,225,1002,64,2,64,109,-3,1206,6,241,1001,64,1,64,1105,1,243,4,231,1002,64,2,64,109,-17,2108,30,4,63,1005,63,259,1106,0,265,4,249,1001,64,1,64,1002,64,2,64,109,14,2108,35,-9,63,1005,63,283,4,271,1105,1,287,1001,64,1,64,1002,64,2,64,109,13,2105,1,-2,1001,64,1,64,1106,0,305,4,293,1002,64,2,64,109,-28,1208,5,32,63,1005,63,327,4,311,1001,64,1,64,1106,0,327,1002,64,2,64,109,12,2102,1,0,63,1008,63,31,63,1005,63,353,4,333,1001,64,1,64,1105,1,353,1002,64,2,64,109,7,21102,41,1,-6,1008,1010,40,63,1005,63,373,1105,1,379,4,359,1001,64,1,64,1002,64,2,64,109,-4,2102,1,-6,63,1008,63,35,63,1005,63,403,1001,64,1,64,1105,1,405,4,385,1002,64,2,64,109,11,21107,42,43,-4,1005,1019,427,4,411,1001,64,1,64,1105,1,427,1002,64,2,64,109,-10,1206,7,445,4,433,1001,64,1,64,1105,1,445,1002,64,2,64,109,10,2105,1,1,4,451,1105,1,463,1001,64,1,64,1002,64,2,64,109,-14,21108,43,42,4,1005,1013,479,1106,0,485,4,469,1001,64,1,64,1002,64,2,64,109,12,2106,0,6,1106,0,503,4,491,1001,64,1,64,1002,64,2,64,109,-10,2107,30,-2,63,1005,63,521,4,509,1106,0,525,1001,64,1,64,1002,64,2,64,109,-7,2101,0,-4,63,1008,63,26,63,1005,63,549,1001,64,1,64,1106,0,551,4,531,1002,64,2,64,109,13,21107,44,43,-3,1005,1014,571,1001,64,1,64,1105,1,573,4,557,1002,64,2,64,109,-6,21108,45,45,1,1005,1012,591,4,579,1106,0,595,1001,64,1,64,1002,64,2,64,109,8,1205,2,609,4,601,1106,0,613,1001,64,1,64,1002,64,2,64,109,-11,1208,-6,34,63,1005,63,629,1106,0,635,4,619,1001,64,1,64,1002,64,2,64,109,-15,2107,33,9,63,1005,63,651,1106,0,657,4,641,1001,64,1,64,1002,64,2,64,109,9,1207,2,38,63,1005,63,677,1001,64,1,64,1106,0,679,4,663,1002,64,2,64,109,8,21101,46,0,0,1008,1010,45,63,1005,63,703,1001,64,1,64,1106,0,705,4,685,1002,64,2,64,109,-5,1201,-3,0,63,1008,63,32,63,1005,63,727,4,711,1106,0,731,1001,64,1,64,1002,64,2,64,109,-6,1207,8,34,63,1005,63,753,4,737,1001,64,1,64,1106,0,753,1002,64,2,64,109,29,1205,-8,765,1106,0,771,4,759,1001,64,1,64,1002,64,2,64,109,-18,1202,-6,1,63,1008,63,39,63,1005,63,797,4,777,1001,64,1,64,1106,0,797,1002,64,2,64,109,8,21101,47,0,0,1008,1018,47,63,1005,63,823,4,803,1001,64,1,64,1105,1,823,1002,64,2,64,109,-12,2101,0,-3,63,1008,63,35,63,1005,63,845,4,829,1106,0,849,1001,64,1,64,1002,64,2,64,109,-9,1201,5,0,63,1008,63,30,63,1005,63,869,1105,1,875,4,855,1001,64,1,64,1002,64,2,64,109,8,1202,-2,1,63,1008,63,34,63,1005,63,899,1001,64,1,64,1105,1,901,4,881,4,64,99,21101,27,0,1,21101,0,915,0,1105,1,922,21201,1,45467,1,204,1,99,109,3,1207,-2,3,63,1005,63,964,21201,-2,-1,1,21101,942,0,0,1106,0,922,21201,1,0,-1,21201,-2,-3,1,21102,1,957,0,1105,1,922,22201,1,-1,-2,1105,1,968,22101,0,-2,-2,109,-3,2106,0,0

View file

@ -78,6 +78,7 @@ mod tests {
assert_eq!(program, &[2, 0, 0, 0, 99]) assert_eq!(program, &[2, 0, 0, 0, 99])
} }
#[test] #[test]
fn test_example4() { fn test_example4() {
let input = "1,1,1,4,99,5,6,0,99"; let input = "1,1,1,4,99,5,6,0,99";

53
2019/src/bin/day9.rs Normal file
View file

@ -0,0 +1,53 @@
use std::{fs, io};
use advent_of_code::computer::Computer;
use advent_of_code::input;
fn main() -> io::Result<()> {
let input = fs::read_to_string("input/day9.txt")?;
let program = input::read_separated_line(',', &input)?;
let mut computer = Computer::new('1', program.clone(), vec![1], vec![]);
computer.run(None, None);
println!("Part 1: {}", computer.output());
// let mut computer = computer::Computer::new('2', data.clone(), vec![5], vec![]);
// computer.run(None, None);
// println!("Part 2: {}", computer.output());
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_relative_example1() {
let program = vec![1102, 34915192, 34915192, 7, 4, 7, 99, 0];
let mut computer = Computer::new('T', program, vec![], vec![]);
computer.run(None, None);
assert_eq!(computer.output(), 1219070632396864);
}
#[test]
fn test_relative_example2() {
let program = vec![
109, 1, 204, -1, 1001, 100, 1, 100, 1008, 100, 16, 101, 1006, 101, 0, 99,
];
let mut computer = Computer::new('T', program, vec![], vec![]);
computer.run(None, None);
assert_eq!(computer.output(), 99);
}
#[test]
fn test_relative_example3() {
let program = vec![104, 1125899906842624, 99];
let mut computer = Computer::new('T', program, vec![], vec![]);
computer.run(None, None);
assert_eq!(computer.output(), 1125899906842624);
}
}

View file

@ -1,32 +1,35 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::convert::TryFrom;
use std::rc::Rc; use std::rc::Rc;
type Address = i32; type Address = i64;
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
enum Instruction { enum Instruction {
Add(Mode, Mode), Add(Mode, Mode, Mode),
Multiply(Mode, Mode), Multiply(Mode, Mode, Mode),
Input, Input(Mode),
Output(Mode), Output(Mode),
JumpIfTrue(Mode, Mode), JumpIfTrue(Mode, Mode),
JumpIfFalse(Mode, Mode), JumpIfFalse(Mode, Mode),
LessThan(Mode, Mode), LessThan(Mode, Mode, Mode),
Equals(Mode, Mode), Equals(Mode, Mode, Mode),
AdjustRelativeBase(Mode),
Halt, Halt,
} }
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq, Copy, Clone)]
enum Mode { enum Mode {
Immediate, Immediate,
Address, Address,
Relative,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Pipe { pub struct Pipe {
queue: VecDeque<i32>, queue: VecDeque<i64>,
last: Option<i32>, last: Option<i64>,
} }
pub enum ComputeResult { pub enum ComputeResult {
@ -36,57 +39,58 @@ pub enum ComputeResult {
pub struct Computer<I: Input, O: Output> { pub struct Computer<I: Input, O: Output> {
name: char, name: char,
ip: i32, ip: i64,
memory: Vec<i32>, memory: Vec<i64>,
input: I, input: I,
output: O, output: O,
relative_base: i64,
} }
pub trait Input { pub trait Input {
fn read(&mut self) -> Option<i32>; fn read(&mut self) -> Option<i64>;
} }
pub trait Output { pub trait Output {
fn write(&mut self, value: i32); fn write(&mut self, value: i64);
fn last_value(&self) -> i32; fn last_value(&self) -> i64;
} }
impl Input for Vec<i32> { impl Input for Vec<i64> {
fn read(&mut self) -> Option<i32> { fn read(&mut self) -> Option<i64> {
self.pop() self.pop()
} }
} }
impl Output for Vec<i32> { impl Output for Vec<i64> {
fn write(&mut self, value: i32) { fn write(&mut self, value: i64) {
self.push(value) self.push(value)
} }
fn last_value(&self) -> i32 { fn last_value(&self) -> i64 {
*self.last().unwrap() *self.last().unwrap()
} }
} }
impl Input for Rc<RefCell<Pipe>> { impl Input for Rc<RefCell<Pipe>> {
fn read(&mut self) -> Option<i32> { fn read(&mut self) -> Option<i64> {
dbg!(self.borrow_mut().queue.pop_front()) dbg!(self.borrow_mut().queue.pop_front())
} }
} }
impl Output for Rc<RefCell<Pipe>> { impl Output for Rc<RefCell<Pipe>> {
fn write(&mut self, value: i32) { fn write(&mut self, value: i64) {
let mut pipe = self.borrow_mut(); let mut pipe = self.borrow_mut();
pipe.last = Some(value); pipe.last = Some(value);
pipe.queue.push_back(value); pipe.queue.push_back(value);
} }
fn last_value(&self) -> i32 { fn last_value(&self) -> i64 {
self.borrow().last.unwrap() self.borrow().last.unwrap()
} }
} }
fn decode(mut instruction: i32) -> Instruction { fn decode(mut instruction: i64) -> Instruction {
let opcode = divmod(&mut instruction, 100); let opcode = divmod(&mut instruction, 100);
match opcode { match opcode {
@ -96,13 +100,15 @@ fn decode(mut instruction: i32) -> Instruction {
Instruction::Add( Instruction::Add(
Mode::from(divmod(&mut instruction, 10)), Mode::from(divmod(&mut instruction, 10)),
Mode::from(divmod(&mut instruction, 10)), Mode::from(divmod(&mut instruction, 10)),
Mode::from(divmod(&mut instruction, 10)),
) )
} }
2 => Instruction::Multiply( 2 => Instruction::Multiply(
Mode::from(divmod(&mut instruction, 10)), Mode::from(divmod(&mut instruction, 10)),
Mode::from(divmod(&mut instruction, 10)), Mode::from(divmod(&mut instruction, 10)),
Mode::from(divmod(&mut instruction, 10)),
), ),
3 => Instruction::Input, 3 => Instruction::Input(Mode::from(divmod(&mut instruction, 10))),
4 => Instruction::Output(Mode::from(divmod(&mut instruction, 10))), 4 => Instruction::Output(Mode::from(divmod(&mut instruction, 10))),
5 => Instruction::JumpIfTrue( 5 => Instruction::JumpIfTrue(
Mode::from(divmod(&mut instruction, 10)), Mode::from(divmod(&mut instruction, 10)),
@ -115,11 +121,14 @@ fn decode(mut instruction: i32) -> Instruction {
7 => Instruction::LessThan( 7 => Instruction::LessThan(
Mode::from(divmod(&mut instruction, 10)), Mode::from(divmod(&mut instruction, 10)),
Mode::from(divmod(&mut instruction, 10)), Mode::from(divmod(&mut instruction, 10)),
Mode::from(divmod(&mut instruction, 10)),
), ),
8 => Instruction::Equals( 8 => Instruction::Equals(
Mode::from(divmod(&mut instruction, 10)), Mode::from(divmod(&mut instruction, 10)),
Mode::from(divmod(&mut instruction, 10)), Mode::from(divmod(&mut instruction, 10)),
Mode::from(divmod(&mut instruction, 10)),
), ),
9 => Instruction::AdjustRelativeBase(Mode::from(divmod(&mut instruction, 10))),
99 => Instruction::Halt, 99 => Instruction::Halt,
_ => panic!("Invalid opcode: {}", opcode), _ => panic!("Invalid opcode: {}", opcode),
} }
@ -130,13 +139,17 @@ where
I: Input, I: Input,
O: Output, O: Output,
{ {
pub fn new(name: char, memory: Vec<i32>, input: I, output: O) -> Self { pub fn new(name: char, mut memory: Vec<i64>, input: I, output: O) -> Self {
// HACK
let mut buffer = vec![0; 64 * 1024 * 1024];
memory.append(&mut buffer);
Computer { Computer {
name, name,
ip: 0, ip: 0,
memory, memory,
input, input,
output, output,
relative_base: 0,
} }
} }
@ -144,41 +157,52 @@ where
self.name self.name
} }
fn read(&self, value: i32, mode: Mode) -> i32 { fn read(&self, value: i64, mode: Mode) -> i64 {
match mode { match mode {
Mode::Immediate => self.memory[value as usize], Mode::Immediate => self.memory[value as usize],
Mode::Address => self.memory[self.memory[value as usize] as usize], Mode::Address => self.memory[self.memory[value as usize] as usize],
// The address a relative mode parameter refers to is itself plus the current relative base.
Mode::Relative => {
self.memory
[usize::try_from(self.relative_base + self.memory[value as usize]).unwrap()]
}
} }
} }
fn write(&mut self, address: Address, value: i32) { fn write(&mut self, address: Address, value: i64, mode: Mode) {
self.memory[address as usize] = value; match mode {
Mode::Immediate => panic!("attempt to write with immediate mode"),
Mode::Address => self.memory[address as usize] = value,
Mode::Relative => {
self.memory[usize::try_from(self.relative_base + address).unwrap()] = value
}
}
} }
pub fn run(&mut self, noun: Option<i32>, verb: Option<i32>) -> ComputeResult { pub fn run(&mut self, noun: Option<i64>, verb: Option<i64>) -> ComputeResult {
println!("{}: resume ip = {}", self.name, self.ip); println!("{}: resume ip = {}", self.name, self.ip);
if let Some(noun) = noun { if let Some(noun) = noun {
self.write(1, noun); self.write(1, noun, Mode::Address);
} }
if let Some(verb) = verb { if let Some(verb) = verb {
self.write(2, verb); self.write(2, verb, Mode::Address);
} }
loop { loop {
match decode(self.read(self.ip, Mode::Immediate)) { match decode(self.read(self.ip, Mode::Immediate)) {
Instruction::Add(mode1, mode2) => { Instruction::Add(mode1, mode2, write_mode) => {
let result = self.read(self.ip + 1, mode1) + self.read(self.ip + 2, mode2); let result = self.read(self.ip + 1, mode1) + self.read(self.ip + 2, mode2);
self.write(self.read(self.ip + 3, Mode::Immediate), result); self.write(self.read(self.ip + 3, Mode::Immediate), result, write_mode);
self.ip += 4; self.ip += 4;
} }
Instruction::Multiply(mode1, mode2) => { Instruction::Multiply(mode1, mode2, write_mode) => {
let result = self.read(self.ip + 1, mode1) * self.read(self.ip + 2, mode2); let result = self.read(self.ip + 1, mode1) * self.read(self.ip + 2, mode2);
self.write(self.read(self.ip + 3, Mode::Immediate), result); self.write(self.read(self.ip + 3, Mode::Immediate), result, write_mode);
self.ip += 4; self.ip += 4;
} }
Instruction::Input => match self.input.read() { Instruction::Input(write_mode) => match self.input.read() {
Some(value) => { Some(value) => {
self.write(self.read(self.ip + 1, Mode::Immediate), value); self.write(self.read(self.ip + 1, Mode::Immediate), value, write_mode);
self.ip += 2; self.ip += 2;
} }
None => { None => {
@ -206,53 +230,60 @@ where
self.ip += 3; self.ip += 3;
} }
} }
Instruction::LessThan(mode1, mode2) => { Instruction::LessThan(mode1, mode2, write_mode) => {
if self.read(self.ip + 1, mode1) < self.read(self.ip + 2, mode2) { if self.read(self.ip + 1, mode1) < self.read(self.ip + 2, mode2) {
self.write(self.read(self.ip + 3, Mode::Immediate), 1); self.write(self.read(self.ip + 3, Mode::Immediate), 1, write_mode);
} else { } else {
self.write(self.read(self.ip + 3, Mode::Immediate), 0); self.write(self.read(self.ip + 3, Mode::Immediate), 0, write_mode);
} }
self.ip += 4; self.ip += 4;
} }
Instruction::Equals(mode1, mode2) => { Instruction::Equals(mode1, mode2, write_mode) => {
if self.read(self.ip + 1, mode1) == self.read(self.ip + 2, mode2) { if self.read(self.ip + 1, mode1) == self.read(self.ip + 2, mode2) {
self.write(self.read(self.ip + 3, Mode::Immediate), 1); self.write(self.read(self.ip + 3, Mode::Immediate), 1, write_mode);
} else { } else {
self.write(self.read(self.ip + 3, Mode::Immediate), 0); self.write(self.read(self.ip + 3, Mode::Immediate), 0, write_mode);
} }
self.ip += 4; self.ip += 4;
} }
Instruction::AdjustRelativeBase(mode) => {
let base = self.read(self.ip + 1, mode);
self.relative_base += base;
self.relative_base;
self.ip += 2;
}
Instruction::Halt => return ComputeResult::Halted, Instruction::Halt => return ComputeResult::Halted,
} }
} }
} }
pub fn output(&self) -> i32 { pub fn output(&self) -> i64 {
self.output.last_value() self.output.last_value()
} }
} }
impl Pipe { impl Pipe {
pub fn new(queue: VecDeque<i32>) -> Self { pub fn new(queue: VecDeque<i64>) -> Self {
Pipe { queue, last: None } Pipe { queue, last: None }
} }
pub fn push_front(&mut self, value: i32) { pub fn push_front(&mut self, value: i64) {
self.queue.push_front(value); self.queue.push_front(value);
} }
} }
fn divmod(value: &mut i32, divisor: i32) -> i32 { fn divmod(value: &mut i64, divisor: i64) -> i64 {
let res = *value % divisor; let res = *value % divisor;
*value /= divisor; *value /= divisor;
res res
} }
impl From<i32> for Mode { impl From<i64> for Mode {
fn from(mode: i32) -> Self { fn from(mode: i64) -> Self {
match mode { match mode {
0 => Mode::Address, 0 => Mode::Address,
1 => Mode::Immediate, 1 => Mode::Immediate,
2 => Mode::Relative,
_ => unreachable!(), _ => unreachable!(),
} }
} }
@ -268,7 +299,7 @@ mod tests {
fn test_decode() { fn test_decode() {
assert_eq!( assert_eq!(
decode(1002), decode(1002),
Instruction::Multiply(Mode::Address, Mode::Immediate) Instruction::Multiply(Mode::Address, Mode::Immediate, Mode::Address)
) )
} }

View file

@ -18,7 +18,7 @@ pub fn read_number_list<P: AsRef<Path>>(path: P) -> io::Result<Vec<i32>> {
Ok(output) Ok(output)
} }
pub fn read_separated_line(sep: char, line: &str) -> io::Result<Vec<i32>> { pub fn read_separated_line(sep: char, line: &str) -> io::Result<Vec<i64>> {
line.trim() line.trim()
.split(sep) .split(sep)
.map(|number| { .map(|number| {