mirror of
https://github.com/wezm/advent-of-code.git
synced 2024-12-18 18:29:55 +00:00
Day 9 part 1
This commit is contained in:
parent
52fe8eb76f
commit
9a7817e6ff
5 changed files with 137 additions and 51 deletions
1
2019/input/day9.txt
Normal file
1
2019/input/day9.txt
Normal 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
|
|
@ -78,6 +78,7 @@ mod tests {
|
|||
|
||||
assert_eq!(program, &[2, 0, 0, 0, 99])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_example4() {
|
||||
let input = "1,1,1,4,99,5,6,0,99";
|
||||
|
|
53
2019/src/bin/day9.rs
Normal file
53
2019/src/bin/day9.rs
Normal 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);
|
||||
}
|
||||
}
|
|
@ -1,32 +1,35 @@
|
|||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::convert::TryFrom;
|
||||
use std::rc::Rc;
|
||||
|
||||
type Address = i32;
|
||||
type Address = i64;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
enum Instruction {
|
||||
Add(Mode, Mode),
|
||||
Multiply(Mode, Mode),
|
||||
Input,
|
||||
Add(Mode, Mode, Mode),
|
||||
Multiply(Mode, Mode, Mode),
|
||||
Input(Mode),
|
||||
Output(Mode),
|
||||
JumpIfTrue(Mode, Mode),
|
||||
JumpIfFalse(Mode, Mode),
|
||||
LessThan(Mode, Mode),
|
||||
Equals(Mode, Mode),
|
||||
LessThan(Mode, Mode, Mode),
|
||||
Equals(Mode, Mode, Mode),
|
||||
AdjustRelativeBase(Mode),
|
||||
Halt,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
||||
enum Mode {
|
||||
Immediate,
|
||||
Address,
|
||||
Relative,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Pipe {
|
||||
queue: VecDeque<i32>,
|
||||
last: Option<i32>,
|
||||
queue: VecDeque<i64>,
|
||||
last: Option<i64>,
|
||||
}
|
||||
|
||||
pub enum ComputeResult {
|
||||
|
@ -36,57 +39,58 @@ pub enum ComputeResult {
|
|||
|
||||
pub struct Computer<I: Input, O: Output> {
|
||||
name: char,
|
||||
ip: i32,
|
||||
memory: Vec<i32>,
|
||||
ip: i64,
|
||||
memory: Vec<i64>,
|
||||
input: I,
|
||||
output: O,
|
||||
relative_base: i64,
|
||||
}
|
||||
|
||||
pub trait Input {
|
||||
fn read(&mut self) -> Option<i32>;
|
||||
fn read(&mut self) -> Option<i64>;
|
||||
}
|
||||
|
||||
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> {
|
||||
fn read(&mut self) -> Option<i32> {
|
||||
impl Input for Vec<i64> {
|
||||
fn read(&mut self) -> Option<i64> {
|
||||
self.pop()
|
||||
}
|
||||
}
|
||||
|
||||
impl Output for Vec<i32> {
|
||||
fn write(&mut self, value: i32) {
|
||||
impl Output for Vec<i64> {
|
||||
fn write(&mut self, value: i64) {
|
||||
self.push(value)
|
||||
}
|
||||
|
||||
fn last_value(&self) -> i32 {
|
||||
fn last_value(&self) -> i64 {
|
||||
*self.last().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
impl Output for Rc<RefCell<Pipe>> {
|
||||
fn write(&mut self, value: i32) {
|
||||
fn write(&mut self, value: i64) {
|
||||
let mut pipe = self.borrow_mut();
|
||||
pipe.last = Some(value);
|
||||
pipe.queue.push_back(value);
|
||||
}
|
||||
|
||||
fn last_value(&self) -> i32 {
|
||||
fn last_value(&self) -> i64 {
|
||||
self.borrow().last.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
fn decode(mut instruction: i32) -> Instruction {
|
||||
fn decode(mut instruction: i64) -> Instruction {
|
||||
let opcode = divmod(&mut instruction, 100);
|
||||
|
||||
match opcode {
|
||||
|
@ -96,13 +100,15 @@ fn decode(mut instruction: i32) -> Instruction {
|
|||
Instruction::Add(
|
||||
Mode::from(divmod(&mut instruction, 10)),
|
||||
Mode::from(divmod(&mut instruction, 10)),
|
||||
Mode::from(divmod(&mut instruction, 10)),
|
||||
)
|
||||
}
|
||||
2 => Instruction::Multiply(
|
||||
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))),
|
||||
5 => Instruction::JumpIfTrue(
|
||||
Mode::from(divmod(&mut instruction, 10)),
|
||||
|
@ -115,11 +121,14 @@ fn decode(mut instruction: i32) -> Instruction {
|
|||
7 => Instruction::LessThan(
|
||||
Mode::from(divmod(&mut instruction, 10)),
|
||||
Mode::from(divmod(&mut instruction, 10)),
|
||||
Mode::from(divmod(&mut instruction, 10)),
|
||||
),
|
||||
8 => Instruction::Equals(
|
||||
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,
|
||||
_ => panic!("Invalid opcode: {}", opcode),
|
||||
}
|
||||
|
@ -130,13 +139,17 @@ where
|
|||
I: Input,
|
||||
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 {
|
||||
name,
|
||||
ip: 0,
|
||||
memory,
|
||||
input,
|
||||
output,
|
||||
relative_base: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,41 +157,52 @@ where
|
|||
self.name
|
||||
}
|
||||
|
||||
fn read(&self, value: i32, mode: Mode) -> i32 {
|
||||
fn read(&self, value: i64, mode: Mode) -> i64 {
|
||||
match mode {
|
||||
Mode::Immediate => self.memory[value 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) {
|
||||
self.memory[address as usize] = value;
|
||||
fn write(&mut self, address: Address, value: i64, mode: Mode) {
|
||||
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);
|
||||
if let Some(noun) = noun {
|
||||
self.write(1, noun);
|
||||
self.write(1, noun, Mode::Address);
|
||||
}
|
||||
if let Some(verb) = verb {
|
||||
self.write(2, verb);
|
||||
self.write(2, verb, Mode::Address);
|
||||
}
|
||||
|
||||
loop {
|
||||
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);
|
||||
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;
|
||||
}
|
||||
Instruction::Multiply(mode1, mode2) => {
|
||||
Instruction::Multiply(mode1, mode2, write_mode) => {
|
||||
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;
|
||||
}
|
||||
Instruction::Input => match self.input.read() {
|
||||
Instruction::Input(write_mode) => match self.input.read() {
|
||||
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;
|
||||
}
|
||||
None => {
|
||||
|
@ -206,53 +230,60 @@ where
|
|||
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) {
|
||||
self.write(self.read(self.ip + 3, Mode::Immediate), 1);
|
||||
self.write(self.read(self.ip + 3, Mode::Immediate), 1, write_mode);
|
||||
} 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;
|
||||
}
|
||||
Instruction::Equals(mode1, mode2) => {
|
||||
Instruction::Equals(mode1, mode2, write_mode) => {
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn output(&self) -> i32 {
|
||||
pub fn output(&self) -> i64 {
|
||||
self.output.last_value()
|
||||
}
|
||||
}
|
||||
|
||||
impl Pipe {
|
||||
pub fn new(queue: VecDeque<i32>) -> Self {
|
||||
pub fn new(queue: VecDeque<i64>) -> Self {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
fn divmod(value: &mut i32, divisor: i32) -> i32 {
|
||||
fn divmod(value: &mut i64, divisor: i64) -> i64 {
|
||||
let res = *value % divisor;
|
||||
*value /= divisor;
|
||||
res
|
||||
}
|
||||
|
||||
impl From<i32> for Mode {
|
||||
fn from(mode: i32) -> Self {
|
||||
impl From<i64> for Mode {
|
||||
fn from(mode: i64) -> Self {
|
||||
match mode {
|
||||
0 => Mode::Address,
|
||||
1 => Mode::Immediate,
|
||||
2 => Mode::Relative,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -268,7 +299,7 @@ mod tests {
|
|||
fn test_decode() {
|
||||
assert_eq!(
|
||||
decode(1002),
|
||||
Instruction::Multiply(Mode::Address, Mode::Immediate)
|
||||
Instruction::Multiply(Mode::Address, Mode::Immediate, Mode::Address)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ pub fn read_number_list<P: AsRef<Path>>(path: P) -> io::Result<Vec<i32>> {
|
|||
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()
|
||||
.split(sep)
|
||||
.map(|number| {
|
||||
|
|
Loading…
Reference in a new issue