Skip to content

Commit

Permalink
Year 2019 Day 9
Browse files Browse the repository at this point in the history
  • Loading branch information
maneatingape committed Sep 1, 2023
1 parent 79ce632 commit bf8480f
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 102 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ pie
| 6 | [Universal Orbit Map](https://adventofcode.com/2019/day/6) | [Source](src/year2019/day06.rs) | 28 |
| 7 | [Amplification Circuit](https://adventofcode.com/2019/day/7) | [Source](src/year2019/day07.rs) | 30000 |
| 8 | [Space Image Format](https://adventofcode.com/2019/day/8) | [Source](src/year2019/day08.rs) | 5 |
| 9 | [Sensor Boost](https://adventofcode.com/2019/day/9) | [Source](src/year2019/day09.rs) | 3088 |

## 2015

Expand Down
1 change: 1 addition & 0 deletions benches/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ mod year2019 {
benchmark!(year2019, day06);
benchmark!(year2019, day07);
benchmark!(year2019, day08);
benchmark!(year2019, day09);
}

mod year2015 {
Expand Down
1 change: 1 addition & 0 deletions input/year2019/day09.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1102,34463338,34463338,63,1007,63,34463338,63,1005,63,53,1101,3,0,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,27,0,1014,1101,286,0,1023,1102,1,35,1018,1102,20,1,1000,1101,26,0,1010,1101,0,289,1022,1102,1,30,1019,1102,734,1,1025,1102,1,31,1012,1101,25,0,1001,1102,1,1,1021,1101,0,36,1002,1101,0,527,1028,1101,895,0,1026,1102,1,23,1016,1101,21,0,1003,1102,22,1,1011,1102,1,522,1029,1102,1,892,1027,1102,1,0,1020,1102,1,28,1015,1102,38,1,1006,1101,0,32,1008,1101,743,0,1024,1101,0,37,1007,1102,1,24,1013,1102,1,33,1009,1102,39,1,1004,1102,1,34,1005,1102,1,29,1017,109,19,21102,40,1,-3,1008,1016,40,63,1005,63,203,4,187,1106,0,207,1001,64,1,64,1002,64,2,64,109,-7,2101,0,-7,63,1008,63,32,63,1005,63,227,1106,0,233,4,213,1001,64,1,64,1002,64,2,64,109,-3,2108,37,-2,63,1005,63,255,4,239,1001,64,1,64,1105,1,255,1002,64,2,64,109,11,21108,41,40,-6,1005,1014,275,1001,64,1,64,1106,0,277,4,261,1002,64,2,64,109,10,2105,1,-7,1105,1,295,4,283,1001,64,1,64,1002,64,2,64,109,-27,1201,-2,0,63,1008,63,25,63,1005,63,321,4,301,1001,64,1,64,1105,1,321,1002,64,2,64,109,15,21107,42,41,0,1005,1018,341,1001,64,1,64,1106,0,343,4,327,1002,64,2,64,109,-25,2108,20,10,63,1005,63,359,1105,1,365,4,349,1001,64,1,64,1002,64,2,64,109,12,2107,35,0,63,1005,63,385,1001,64,1,64,1106,0,387,4,371,1002,64,2,64,109,4,21101,43,0,6,1008,1015,43,63,1005,63,409,4,393,1106,0,413,1001,64,1,64,1002,64,2,64,109,9,21101,44,0,-8,1008,1010,46,63,1005,63,437,1001,64,1,64,1106,0,439,4,419,1002,64,2,64,109,5,21108,45,45,-4,1005,1019,457,4,445,1106,0,461,1001,64,1,64,1002,64,2,64,109,-22,2102,1,7,63,1008,63,33,63,1005,63,481,1106,0,487,4,467,1001,64,1,64,1002,64,2,64,109,14,21102,46,1,-1,1008,1014,43,63,1005,63,507,1106,0,513,4,493,1001,64,1,64,1002,64,2,64,109,12,2106,0,1,4,519,1106,0,531,1001,64,1,64,1002,64,2,64,109,-17,1205,10,547,1001,64,1,64,1106,0,549,4,537,1002,64,2,64,109,-8,1202,-2,1,63,1008,63,17,63,1005,63,569,1105,1,575,4,555,1001,64,1,64,1002,64,2,64,109,23,1206,-5,593,4,581,1001,64,1,64,1105,1,593,1002,64,2,64,109,-14,1208,-8,24,63,1005,63,613,1001,64,1,64,1105,1,615,4,599,1002,64,2,64,109,-2,1207,-1,33,63,1005,63,633,4,621,1105,1,637,1001,64,1,64,1002,64,2,64,109,2,21107,47,48,5,1005,1016,659,4,643,1001,64,1,64,1105,1,659,1002,64,2,64,109,-11,1208,8,32,63,1005,63,681,4,665,1001,64,1,64,1106,0,681,1002,64,2,64,109,2,2101,0,0,63,1008,63,36,63,1005,63,703,4,687,1106,0,707,1001,64,1,64,1002,64,2,64,109,12,1206,7,719,1106,0,725,4,713,1001,64,1,64,1002,64,2,64,109,2,2105,1,8,4,731,1001,64,1,64,1106,0,743,1002,64,2,64,109,-21,2102,1,9,63,1008,63,39,63,1005,63,769,4,749,1001,64,1,64,1105,1,769,1002,64,2,64,109,11,1201,-3,0,63,1008,63,24,63,1005,63,793,1001,64,1,64,1105,1,795,4,775,1002,64,2,64,109,20,1205,-5,809,4,801,1105,1,813,1001,64,1,64,1002,64,2,64,109,-23,1207,4,36,63,1005,63,833,1001,64,1,64,1105,1,835,4,819,1002,64,2,64,109,-3,2107,33,5,63,1005,63,853,4,841,1106,0,857,1001,64,1,64,1002,64,2,64,109,16,1202,-9,1,63,1008,63,37,63,1005,63,879,4,863,1105,1,883,1001,64,1,64,1002,64,2,64,109,12,2106,0,-1,1105,1,901,4,889,1001,64,1,64,4,64,99,21101,0,27,1,21101,0,915,0,1106,0,922,21201,1,48476,1,204,1,99,109,3,1207,-2,3,63,1005,63,964,21201,-2,-1,1,21101,0,942,0,1105,1,922,21202,1,1,-1,21201,-2,-3,1,21101,0,957,0,1105,1,922,22201,1,-1,-2,1106,0,968,21202,-2,1,-2,109,-3,2106,0,0
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ pub mod year2019 {
pub mod day06;
pub mod day07;
pub mod day08;
pub mod day09;
}

/// # Help Santa by solving puzzles to fix the weather machine's snow function.
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ fn all_solutions() -> Vec<Solution> {
solution!(year2019, day06),
solution!(year2019, day07),
solution!(year2019, day08),
solution!(year2019, day09),
// 2015
solution!(year2015, day01),
solution!(year2015, day02),
Expand Down
101 changes: 2 additions & 99 deletions src/year2019/day05.rs
Original file line number Diff line number Diff line change
@@ -1,103 +1,6 @@
//! # Sunny with a Chance of Asteroids
use super::day09::intcode::*; // Time travel
use crate::util::parse::*;
use std::sync::mpsc::*;
use std::thread;

pub struct IntCode {
pc: usize,
code: Vec<i64>,
input_rx: Receiver<i64>,
output_tx: Sender<i64>,
}

impl IntCode {
const FACTOR: [i64; 4] = [0, 100, 1000, 10000];

pub fn spawn(code: &[i64]) -> (Sender<i64>, Receiver<i64>) {
let pc = 0;
let code = code.to_vec();
let (input_tx, input_rx) = channel();
let (output_tx, output_rx) = channel();

let mut computer = IntCode { pc, code, input_rx, output_tx };
thread::spawn(move || computer.run());

(input_tx, output_rx)
}

fn run(&mut self) {
loop {
let op = self.code[self.pc];

match op % 100 {
1 => {
let value = self.read(1) + self.read(2);
self.write(3, value);
self.pc += 4;
}
2 => {
let value = self.read(1) * self.read(2);
self.write(3, value);
self.pc += 4;
}
3 => {
let value = self.input_rx.recv().unwrap();
self.write(1, value);
self.pc += 2;
}
4 => {
let value = self.read(1);
let _ = self.output_tx.send(value);
self.pc += 2;
}
5 => {
let first = self.read(1);
let second = self.read(2);
self.pc = if first == 0 { self.pc + 3 } else { second as usize };
}
6 => {
let first = self.read(1);
let second = self.read(2);
self.pc = if first == 0 { second as usize } else { self.pc + 3 };
}
7 => {
let value = self.read(1) < self.read(2);
self.write(3, value as i64);
self.pc += 4;
}
8 => {
let value = self.read(1) == self.read(2);
self.write(3, value as i64);
self.pc += 4;
}
_ => break,
}
}
}

fn read(&self, offset: usize) -> i64 {
let mode = self.code[self.pc] / Self::FACTOR[offset];

let index = match mode % 10 {
0 => self.code[self.pc + offset] as usize,
1 => self.pc + offset,
_ => unreachable!(),
};

self.code[index]
}

fn write(&mut self, offset: usize, value: i64) {
let mode = self.code[self.pc] / Self::FACTOR[offset];

let index = match mode % 10 {
0 => self.code[self.pc + offset],
_ => unreachable!(),
};

self.code[index as usize] = value;
}
}

pub fn parse(input: &str) -> Vec<i64> {
input.iter_signed().collect()
Expand All @@ -114,7 +17,7 @@ pub fn part2(input: &[i64]) -> i64 {
/// Start `IntCode` computer in its own thread, sending a single initial value.
/// Receives multiple values from the output channel returning only the last one.
fn run(input: &[i64], value: i64) -> i64 {
let (tx, rx) = IntCode::spawn(input);
let (tx, rx) = Computer::spawn(input);
let _ = tx.send(value);

let mut result = 0;
Expand Down
6 changes: 3 additions & 3 deletions src/year2019/day07.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
//! [`permutations`]: crate::util::slice
//! [`Sender`]: std::sync::mpsc::Sender
//! [`Receiver`]: std::sync::mpsc::Receiver
use super::day05::IntCode;
use super::day09::intcode::*; // Time travel
use crate::util::parse::*;
use crate::util::slice::*;

Expand All @@ -26,7 +26,7 @@ pub fn part1(input: &[i64]) -> i64 {

// Send exactly 2 inputs and receive exactly 1 output per amplifier.
for &phase in slice {
let (tx, rx) = IntCode::spawn(input);
let (tx, rx) = Computer::spawn(input);
let _ = tx.send(phase);
let _ = tx.send(signal);
signal = rx.recv().unwrap();
Expand All @@ -43,7 +43,7 @@ pub fn part2(input: &[i64]) -> i64 {
let mut result = 0;

let feedback = |slice: &[i64]| {
let (senders, receivers): (Vec<_>, Vec<_>) = (0..5).map(|_| IntCode::spawn(input)).unzip();
let (senders, receivers): (Vec<_>, Vec<_>) = (0..5).map(|_| Computer::spawn(input)).unzip();

// Send each initial phase setting exactly once.
for (tx, &phase) in senders.iter().zip(slice.iter()) {
Expand Down
149 changes: 149 additions & 0 deletions src/year2019/day09.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
//! # Sensor Boost
//!
//! This problem is essentially an unit test for the canonical full intcode computer
//! used heavily by other days.
use crate::util::parse::*;
use intcode::*;

pub mod intcode {
use std::sync::mpsc::*;
use std::thread;

pub struct Computer {
pc: usize,
base: i64,
code: Vec<i64>,
input_rx: Receiver<i64>,
output_tx: Sender<i64>,
}

impl Computer {
/// Spawns an `IntCode` computer in a new thread, returning an input and output channel
/// for communicating asynchronously with the computer via the opcodes 3 and 4.
pub fn spawn(code: &[i64]) -> (Sender<i64>, Receiver<i64>) {
let pc = 0;
let base = 0;
let code = code.to_vec();
let (input_tx, input_rx) = channel();
let (output_tx, output_rx) = channel();

let mut computer = Computer { pc, base, code, input_rx, output_tx };
thread::spawn(move || computer.run());

(input_tx, output_rx)
}

/// Runs until a `99` opcode instruction is encountered.
fn run(&mut self) {
loop {
match self.code[self.pc] % 100 {
// Add
1 => {
let value = self.read(1) + self.read(2);
self.write(3, value);
self.pc += 4;
}
// Multiply
2 => {
let value = self.read(1) * self.read(2);
self.write(3, value);
self.pc += 4;
}
// Read input channel
3 => {
let value = self.input_rx.recv().unwrap();
self.write(1, value);
self.pc += 2;
}
// Write output channel
4 => {
let value = self.read(1);
let _ = self.output_tx.send(value);
self.pc += 2;
}
// Jump if true
5 => {
let first = self.read(1);
let second = self.read(2);
self.pc = if first == 0 { self.pc + 3 } else { second as usize };
}
// Jump if false
6 => {
let first = self.read(1);
let second = self.read(2);
self.pc = if first == 0 { second as usize } else { self.pc + 3 };
}
// Less than
7 => {
let value = self.read(1) < self.read(2);
self.write(3, value as i64);
self.pc += 4;
}
// Equals
8 => {
let value = self.read(1) == self.read(2);
self.write(3, value as i64);
self.pc += 4;
}
// Adjust relative base
9 => {
let value = self.read(1);
self.base += value;
self.pc += 2;
}
_ => break,
}
}
}

/// Convenience wrapper for reading a value
fn read(&mut self, offset: usize) -> i64 {
let index = self.address(offset);
self.code[index]
}

/// Convenience wrapper for writing a value
fn write(&mut self, offset: usize, value: i64) {
let index = self.address(offset);
self.code[index] = value;
}

/// Calculates an address using one of the three possible address modes.
/// If the address exceeds the size of the `code` vector then it is extended with 0 values.
fn address(&mut self, offset: usize) -> usize {
const FACTOR: [i64; 4] = [0, 100, 1000, 10000];
let mode = self.code[self.pc] / FACTOR[offset];

let index = match mode % 10 {
0 => self.code[self.pc + offset] as usize,
1 => self.pc + offset,
2 => (self.base + self.code[self.pc + offset]) as usize,
_ => unreachable!(),
};

if index >= self.code.len() {
self.code.resize(index + 1, 0);
}

index
}
}
}

pub fn parse(input: &str) -> Vec<i64> {
input.iter_signed().collect()
}

pub fn part1(input: &[i64]) -> i64 {
run(input, 1)
}

pub fn part2(input: &[i64]) -> i64 {
run(input, 2)
}

fn run(input: &[i64], value: i64) -> i64 {
let (tx, rx) = Computer::spawn(input);
let _ = tx.send(value);
rx.recv().unwrap()
}
1 change: 1 addition & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ mod year2019 {
mod day06_test;
mod day07_test;
mod day08_test;
mod day09_test;
}

mod year2015 {
Expand Down
16 changes: 16 additions & 0 deletions tests/year2019/day09_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use aoc::year2019::day09::*;

const FIRST_EXAMPLE: &str = "109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99";
const SECOND_EXAMPLE: &str = "1102,34915192,34915192,7,4,7,99,0";

#[test]
fn part1_test() {
let input = parse(FIRST_EXAMPLE);
assert_eq!(part1(&input), 109);
}

#[test]
fn part2_test() {
let input = parse(SECOND_EXAMPLE);
assert_eq!(part2(&input), 1219070632396864);
}

0 comments on commit bf8480f

Please sign in to comment.