summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Wernick <justin@worthe-it.co.za>2019-12-14 20:59:58 +0200
committerJustin Wernick <justin@worthe-it.co.za>2019-12-14 20:59:58 +0200
commit5c60610b768b98113ca8ca5e8f833fa42d5aa4cf (patch)
tree9c4573be2e1d6a626152880e568085d62d3340aa
parent754a9a4e220b039770b12cb0803b0b0ad3133555 (diff)
Intcode computer to use bigints and unlimited memory space!
Also started a more complete error reporting scheme.
-rw-r--r--Cargo.lock84
-rw-r--r--Cargo.toml3
-rw-r--r--src/bin/day_2.rs17
-rw-r--r--src/bin/day_7.rs24
-rw-r--r--src/lib.rs210
5 files changed, 238 insertions, 100 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 30421cf..86f88f1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -15,6 +15,7 @@ dependencies = [
"archery 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"derive_more 0.99.2 (registry+https://github.com/rust-lang/crates.io-index)",
"im 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rpds 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -37,6 +38,11 @@ dependencies = [
]
[[package]]
+name = "autocfg"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -100,6 +106,76 @@ version = "0.2.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "num"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num-bigint"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num-complex"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num-iter"
+version = "0.1.39"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num-rational"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "proc-macro-error"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -257,6 +333,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum archery 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d308d8fa3f687f7a7588fccc4812ed6914be09518232f00454693a7417273ad2"
"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
+"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum bitmaps 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81e039a80914325b37fde728ef7693c212f0ac913d5599607d7b95a9484aae0b"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
@@ -264,6 +341,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
"checksum im 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a1f9b6540e530defef7f2df4ed330d45b739b10450548c74a9913f63ea1acc6b"
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
+"checksum num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf4825417e1e1406b3782a8ce92f4d53f26ec055e3622e1881ca8e9f5f9e08db"
+"checksum num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a"
+"checksum num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fcb0cf31fb3ff77e6d2a6ebd6800df7fdcd106f2ad89113c9130bcd07f93dffc"
+"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
+"checksum num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e"
+"checksum num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2885278d5fe2adc2f75ced642d52d879bffaceb5a2e0b1d4309ffdfb239b454"
+"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4"
"checksum proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aeccfe4d5d8ea175d5f0e4a2ad0637e0f4121d63bd99d356fb1f39ab2e7c6097"
"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27"
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
diff --git a/Cargo.toml b/Cargo.toml
index eb300fe..fc97025 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,4 +9,5 @@ structopt = "0.3.5"
derive_more = "0.99.2"
im = "14.0.0"
rpds = "0.7.0"
-archery = "0.3.0" \ No newline at end of file
+archery = "0.3.0"
+num = "0.2" \ No newline at end of file
diff --git a/src/bin/day_2.rs b/src/bin/day_2.rs
index ce8fcaa..ba9e189 100644
--- a/src/bin/day_2.rs
+++ b/src/bin/day_2.rs
@@ -41,7 +41,9 @@ fn main() {
match (opt.noun, opt.verb, opt.output) {
(Some(noun), Some(verb), _) => {
let result = exit_on_failed_assertion(
- program.with_noun_verb_input(noun, verb).execute(),
+ program
+ .with_noun_verb_input(noun, verb)
+ .execute_returning_memory_0(),
"Program errored",
);
println!("{}", result);
@@ -52,7 +54,8 @@ fn main() {
println!("({}, {})", noun, verb);
}
(None, None, None) => {
- let result = exit_on_failed_assertion(program.execute(), "Program errored");
+ let result =
+ exit_on_failed_assertion(program.execute_returning_memory_0(), "Program errored");
println!("{}", result);
}
_ => {
@@ -77,17 +80,17 @@ fn find_input(
output: Intcode,
) -> Result<(Intcode, Intcode), IntcodeProgramError> {
(0..99)
- .flat_map(|noun| (0..99).map(move |verb| (noun, verb)))
+ .flat_map(|noun| (0..99).map(move |verb| (Intcode::from(noun), Intcode::from(verb))))
.map(|(noun, verb)| {
(
- noun,
- verb,
+ noun.clone(),
+ verb.clone(),
program
.with_noun_verb_input(noun, verb)
.execute_returning_memory_0(),
)
})
- .find(|(_noun, _verb, out)| *out == Ok(Some(output)))
+ .find(|(_noun, _verb, out)| *out == Ok(output.clone()))
.map(|(noun, verb, _out)| Ok((noun, verb)))
- .unwrap_or(Err(IntcodeProgramError))
+ .unwrap_or(Err(IntcodeProgramError::Unknown))
}
diff --git a/src/bin/day_7.rs b/src/bin/day_7.rs
index 0abf215..9b9177a 100644
--- a/src/bin/day_7.rs
+++ b/src/bin/day_7.rs
@@ -52,12 +52,12 @@ fn find_max_power(
feedback_loop_mode: bool,
) -> Result<Intcode, IntcodeProgramError> {
PhaseSetting::all(feedback_loop_mode)
- .map(|phase| AmplifierArray::new(program, phase).execute())
+ .map(|phase| AmplifierArray::new(program, &phase).execute())
.collect::<Result<Vec<Intcode>, _>>()
- .map(|powers| powers.into_iter().max().unwrap_or(0))
+ .map(|powers| powers.into_iter().max().unwrap_or(Intcode::from(0)))
}
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone)]
struct PhaseSetting([Intcode; 5]);
impl PhaseSetting {
@@ -69,7 +69,7 @@ impl PhaseSetting {
}
}
- fn permute(min: Intcode, max: Intcode) -> impl Iterator<Item = PhaseSetting> {
+ fn permute(min: i32, max: i32) -> impl Iterator<Item = PhaseSetting> {
// This is an absolutely atrocious way to do the permutation,
// but luckily it's only 5 elements long.
(min..max)
@@ -77,12 +77,14 @@ impl PhaseSetting {
(min..max).flat_map(move |b| {
(min..max).flat_map(move |c| {
(min..max).flat_map(move |d| {
- (min..max).map(move |e| PhaseSetting([a, b, c, d, e]))
+ (min..max).map(move |e| {
+ PhaseSetting([a.into(), b.into(), c.into(), d.into(), e.into()])
+ })
})
})
})
})
- .filter(move |phase| (min..max).all(|x| phase.0.contains(&x)))
+ .filter(move |phase| (min..max).all(|x| phase.0.contains(&x.into())))
}
}
@@ -92,7 +94,7 @@ struct AmplifierArray {
}
impl AmplifierArray {
- fn new(program: &IntcodeProgram, phase: PhaseSetting) -> AmplifierArray {
+ fn new(program: &IntcodeProgram, phase: &PhaseSetting) -> AmplifierArray {
AmplifierArray {
amplifiers: (0..5)
.map(|n| AmplifierArray::new_amp(program, phase, n))
@@ -100,11 +102,11 @@ impl AmplifierArray {
}
}
- fn new_amp(program: &IntcodeProgram, phase: PhaseSetting, n: usize) -> IntcodeProgram {
+ fn new_amp(program: &IntcodeProgram, phase: &PhaseSetting, n: usize) -> IntcodeProgram {
if n == 0 {
- program.with_input(list![phase.0[n], 0])
+ program.with_input(list![phase.0[n].clone(), Intcode::from(0)])
} else {
- program.with_input(list![phase.0[n]])
+ program.with_input(list![phase.0[n].clone()])
}
}
@@ -122,7 +124,7 @@ impl AmplifierArray {
self.amplifiers
.first()
.and_then(|amp| amp.input.first().cloned())
- .ok_or(IntcodeProgramError)
+ .ok_or(IntcodeProgramError::Unknown)
}
fn is_terminated(&self) -> bool {
diff --git a/src/lib.rs b/src/lib.rs
index 717505e..5a5f9b3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,18 +1,21 @@
+use num::bigint::BigInt;
+use num::traits::identities::Zero;
+use rpds::RedBlackTreeMap;
use rpds::{list::List, vector::Vector};
use std::fmt;
use std::iter;
use std::iter::FromIterator;
use std::iter::IntoIterator;
-pub type Intcode = i32;
+pub type Intcode = BigInt;
#[derive(Debug, Clone)]
pub struct IntcodeProgram {
- instruction_pointer: usize,
- pub error: bool,
+ instruction_pointer: Intcode,
+ pub error: Option<IntcodeProgramError>,
pub halted: bool,
pub awaiting_input: bool,
- memory: Vector<Intcode>,
+ memory: RedBlackTreeMap<Intcode, Intcode>,
pub input: List<Intcode>,
pub output: Vector<Intcode>,
}
@@ -20,11 +23,15 @@ pub struct IntcodeProgram {
impl FromIterator<Intcode> for IntcodeProgram {
fn from_iter<I: IntoIterator<Item = Intcode>>(iter: I) -> Self {
IntcodeProgram {
- instruction_pointer: 0,
- error: false,
+ instruction_pointer: Intcode::from(0),
+ error: None,
halted: false,
awaiting_input: false,
- memory: iter.into_iter().collect(),
+ memory: iter
+ .into_iter()
+ .enumerate()
+ .map(|(addr, val)| (Intcode::from(addr), val))
+ .collect(),
input: List::new(),
output: Vector::new(),
}
@@ -33,7 +40,8 @@ impl FromIterator<Intcode> for IntcodeProgram {
impl IntcodeProgram {
pub fn with_noun_verb_input(&self, noun: Intcode, verb: Intcode) -> IntcodeProgram {
- self.with_memory_set(1, noun).with_memory_set(2, verb)
+ self.with_memory_set(1.into(), noun)
+ .with_memory_set(2.into(), verb)
}
pub fn with_input(&self, input: List<Intcode>) -> IntcodeProgram {
@@ -61,7 +69,7 @@ impl IntcodeProgram {
self.run_to_termination().output_into_result()
}
- pub fn execute_returning_memory_0(&self) -> Result<Option<Intcode>, IntcodeProgramError> {
+ pub fn execute_returning_memory_0(&self) -> Result<Intcode, IntcodeProgramError> {
self.run_to_termination().memory_0_into_result()
}
@@ -81,7 +89,7 @@ impl IntcodeProgram {
.unwrap()
}
- fn with_instruction_pointer(&self, instruction_pointer: usize) -> IntcodeProgram {
+ fn with_instruction_pointer(&self, instruction_pointer: Intcode) -> IntcodeProgram {
IntcodeProgram {
instruction_pointer,
..self.clone()
@@ -90,19 +98,16 @@ impl IntcodeProgram {
fn with_instruction_pointer_offset(&self, offset: usize) -> IntcodeProgram {
IntcodeProgram {
- instruction_pointer: self.instruction_pointer + offset,
+ instruction_pointer: self.instruction_pointer.clone() + offset,
..self.clone()
}
}
- fn with_memory_set(&self, address: usize, value: Intcode) -> IntcodeProgram {
- self.memory
- .set(address, value)
- .map(|memory| IntcodeProgram {
- memory,
- ..self.clone()
- })
- .unwrap_or(self.error())
+ fn with_memory_set(&self, address: Intcode, value: Intcode) -> IntcodeProgram {
+ IntcodeProgram {
+ memory: self.memory.insert(address, value),
+ ..self.clone()
+ }
}
fn with_input_consumed(&self) -> IntcodeProgram {
@@ -112,7 +117,7 @@ impl IntcodeProgram {
input,
..self.clone()
})
- .unwrap_or(self.error())
+ .unwrap_or(self.error(IntcodeProgramError::Unknown))
}
fn with_output(&self, print: Intcode) -> IntcodeProgram {
@@ -123,25 +128,26 @@ impl IntcodeProgram {
}
fn output_into_result(&self) -> Result<Vector<Intcode>, IntcodeProgramError> {
- if self.error {
- Err(IntcodeProgramError)
- } else {
- Ok(self.output.clone())
+ match self.error {
+ Some(ref error) => Err(error.clone()),
+ None => Ok(self.output.clone()),
}
}
- fn memory_0_into_result(&self) -> Result<Option<Intcode>, IntcodeProgramError> {
- if self.error {
- Err(IntcodeProgramError)
- } else {
- Ok(self.memory.get(0).cloned())
+ fn memory_0_into_result(&self) -> Result<Intcode, IntcodeProgramError> {
+ match self.error {
+ Some(ref error) => Err(error.clone()),
+ None => Ok(self
+ .memory
+ .get(&Intcode::from(0))
+ .cloned()
+ .unwrap_or(Intcode::from(0))),
}
}
fn next(&self) -> IntcodeProgram {
- //eprintln!("{:?}", self);
self.memory
- .get(self.instruction_pointer)
- .map(|&opcode| match opcode % 100 {
+ .get(&self.instruction_pointer)
+ .map(|opcode| match opcode.to_radix_le(100).1[0] {
1 => self.add(opcode),
2 => self.multiply(opcode),
3 => self.input(opcode),
@@ -151,77 +157,79 @@ impl IntcodeProgram {
7 => self.less_than(opcode),
8 => self.equals(opcode),
99 => self.halt(),
- _ => self.error(),
+ unknown => self.error(IntcodeProgramError::InvalidOpcode(unknown.clone())),
})
- .unwrap_or(self.error())
+ .unwrap_or(self.error(IntcodeProgramError::Unknown))
}
- fn add(&self, mode: Intcode) -> IntcodeProgram {
+ fn add(&self, mode: &Intcode) -> IntcodeProgram {
match (self.get(1, mode), self.get(2, mode), self.get_immediate(3)) {
- (Some(in1), Some(in2), Some(out)) => self
+ (in1, in2, out) => self
.with_instruction_pointer_offset(4)
- .with_memory_set(out as usize, in1 + in2),
- _ => self.error(),
+ .with_memory_set(out, in1 + in2),
}
}
- fn multiply(&self, mode: Intcode) -> IntcodeProgram {
+ fn multiply(&self, mode: &Intcode) -> IntcodeProgram {
match (self.get(1, mode), self.get(2, mode), self.get_immediate(3)) {
- (Some(in1), Some(in2), Some(out)) => self
+ (in1, in2, out) => self
.with_instruction_pointer_offset(4)
- .with_memory_set(out as usize, in1 * in2),
- _ => self.error(),
+ .with_memory_set(out, in1 * in2),
}
}
- fn input(&self, _mode: Intcode) -> IntcodeProgram {
+ fn input(&self, _mode: &Intcode) -> IntcodeProgram {
match (self.input.first().cloned(), self.get_immediate(1)) {
- (Some(input), Some(out)) => self
+ (Some(input), out) => self
.with_instruction_pointer_offset(2)
- .with_memory_set(out as usize, input)
+ .with_memory_set(out, input)
.with_input_consumed(),
- (None, Some(_out)) => self.await_input(),
- _ => self.error(),
+ (None, _out) => self.await_input(),
}
}
- fn output(&self, mode: Intcode) -> IntcodeProgram {
+ fn output(&self, mode: &Intcode) -> IntcodeProgram {
match self.get(1, mode) {
- Some(print) => self.with_instruction_pointer_offset(2).with_output(print),
- _ => self.error(),
+ print => self.with_instruction_pointer_offset(2).with_output(print),
}
}
- fn jump_if_true(&self, mode: Intcode) -> IntcodeProgram {
+ fn jump_if_true(&self, mode: &Intcode) -> IntcodeProgram {
match (self.get(1, mode), self.get(2, mode)) {
- (Some(pred), Some(to)) if pred != 0 => self.with_instruction_pointer(to as usize),
- (Some(_), Some(_)) => self.with_instruction_pointer_offset(3),
- _ => self.error(),
+ (ref pred, ref to) if !pred.is_zero() => self.with_instruction_pointer(to.clone()),
+ (_, _) => self.with_instruction_pointer_offset(3),
}
}
- fn jump_if_false(&self, mode: Intcode) -> IntcodeProgram {
+ fn jump_if_false(&self, mode: &Intcode) -> IntcodeProgram {
match (self.get(1, mode), self.get(2, mode)) {
- (Some(pred), Some(to)) if pred == 0 => self.with_instruction_pointer(to as usize),
- (Some(_), Some(_)) => self.with_instruction_pointer_offset(3),
- _ => self.error(),
+ (ref pred, ref to) if pred.is_zero() => self.with_instruction_pointer(to.clone()),
+ (_, _) => self.with_instruction_pointer_offset(3),
}
}
- fn less_than(&self, mode: Intcode) -> IntcodeProgram {
+ fn less_than(&self, mode: &Intcode) -> IntcodeProgram {
match (self.get(1, mode), self.get(2, mode), self.get_immediate(3)) {
- (Some(in1), Some(in2), Some(out)) => self
- .with_instruction_pointer_offset(4)
- .with_memory_set(out as usize, if in1 < in2 { 1 } else { 0 }),
- _ => self.error(),
+ (in1, in2, out) => self.with_instruction_pointer_offset(4).with_memory_set(
+ out,
+ if in1 < in2 {
+ Intcode::from(1)
+ } else {
+ Intcode::from(0)
+ },
+ ),
}
}
- fn equals(&self, mode: Intcode) -> IntcodeProgram {
+ fn equals(&self, mode: &Intcode) -> IntcodeProgram {
match (self.get(1, mode), self.get(2, mode), self.get_immediate(3)) {
- (Some(in1), Some(in2), Some(out)) => self
- .with_instruction_pointer_offset(4)
- .with_memory_set(out as usize, if in1 == in2 { 1 } else { 0 }),
- _ => self.error(),
+ (in1, in2, out) => self.with_instruction_pointer_offset(4).with_memory_set(
+ out,
+ if in1 == in2 {
+ Intcode::from(1)
+ } else {
+ Intcode::from(0)
+ },
+ ),
}
}
@@ -246,41 +254,81 @@ impl IntcodeProgram {
}
}
- fn error(&self) -> IntcodeProgram {
+ fn error(&self, error: IntcodeProgramError) -> IntcodeProgram {
IntcodeProgram {
halted: true,
- error: true,
+ error: Some(error),
..self.clone()
}
}
- fn get(&self, pointer_offset: usize, mode: Intcode) -> Option<Intcode> {
- match mode / (10 as Intcode).pow(pointer_offset as u32 + 1) % 10 {
+ fn get(&self, pointer_offset: usize, mode: &Intcode) -> Intcode {
+ match mode
+ .to_radix_le(10)
+ .1
+ .get(pointer_offset + 2)
+ .cloned()
+ .unwrap_or(0)
+ {
0 => self.get_position(pointer_offset),
1 => self.get_immediate(pointer_offset),
- _ => None,
+ _ => Intcode::from(0), // TODO: Relative mode
}
}
- fn get_immediate(&self, pointer_offset: usize) -> Option<Intcode> {
+ fn get_immediate(&self, pointer_offset: usize) -> Intcode {
self.memory
- .get(self.instruction_pointer + pointer_offset)
+ .get(&(self.instruction_pointer.clone() + pointer_offset))
.cloned()
+ .unwrap_or(Intcode::from(0))
}
- fn get_position(&self, pointer_offset: usize) -> Option<Intcode> {
- self.get_immediate(pointer_offset)
- .and_then(|r| self.memory.get(r as usize))
+ fn get_position(&self, pointer_offset: usize) -> Intcode {
+ self.memory
+ .get(&self.get_immediate(pointer_offset))
.cloned()
+ .unwrap_or(Intcode::from(0))
}
}
-#[derive(Debug, PartialEq)]
-pub struct IntcodeProgramError;
+#[derive(Debug, PartialEq, Clone)]
+pub enum IntcodeProgramError {
+ InvalidOpcode(u8),
+ Unknown,
+}
impl fmt::Display for IntcodeProgramError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "Unknown error")
+ use IntcodeProgramError::*;
+
+ match self {
+ InvalidOpcode(i) => write!(f, "{} is not a valid opcode", i),
+ Unknown => write!(f, "Unknown error"),
+ }
}
}
impl std::error::Error for IntcodeProgramError {}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn day_2_example_1() {
+ let program: IntcodeProgram = vec![1, 0, 0, 0, 99]
+ .into_iter()
+ .map(Intcode::from)
+ .collect::<IntcodeProgram>()
+ .run_to_termination();
+
+ assert_eq!(program.error, None);
+ assert_eq!(
+ program.memory,
+ vec![2, 0, 0, 0, 99]
+ .into_iter()
+ .enumerate()
+ .map(|(i, val)| (Intcode::from(i), Intcode::from(val)))
+ .collect::<RedBlackTreeMap<Intcode, Intcode>>()
+ );
+ }
+}