~janbaudisch/aoc-2019

1ce2ed94699b95ebab713cc6098c1aae005bb8d1 — Jan Baudisch 4 years ago 2c2a69a
add day_02
5 files changed, 132 insertions(+), 1 deletions(-)

M Cargo.lock
M Cargo.toml
A day_02/Cargo.toml
A day_02/src/main.rs
A day_02/src/program.rs
M Cargo.lock => Cargo.lock +7 -0
@@ 10,3 10,10 @@ version = "1.0.0"
dependencies = [
 "common 1.0.0",
]

[[package]]
name = "day_02"
version = "1.0.0"
dependencies = [
 "common 1.0.0",
]

M Cargo.toml => Cargo.toml +2 -1
@@ 1,7 1,8 @@
[workspace]
members = [
    "common",
    "day_01"
    "day_01",
    "day_02"
]

[profile.release]

A day_02/Cargo.toml => day_02/Cargo.toml +12 -0
@@ 0,0 1,12 @@
[package]
name = "day_02"
version = "1.0.0"
description = "Day 2 - Advent of Code 2019"
authors = ["Jan Baudisch <dev@baudisch.xyz>"]
license = "GPL-3.0-or-later"
readme = "../README.md"
edition = "2018"
workspace = ".."

[dependencies]
common = { path = "../common" }

A day_02/src/main.rs => day_02/src/main.rs +20 -0
@@ 0,0 1,20 @@
mod program;

use common::input;
use program::Program;

fn main() {
    let mut program: Program = input::read_line().into();

    println!("[PART ONE] value at position 0: {}", program.run(12, 2));

    'outer: for noun in 0..100 {
        for verb in 0..100 {
            program.reset();
            if program.run(noun, verb) == 19_690_720 {
                println!("[PART TWO] 100 * noun + verb = {}", 100 * noun + verb);
                break 'outer;
            }
        }
    }
}

A day_02/src/program.rs => day_02/src/program.rs +91 -0
@@ 0,0 1,91 @@
enum ExitCode {
    Continue,
    Halt,
}

pub struct Program {
    code: Vec<usize>,
    memory: Vec<usize>,
}

impl Program {
    pub fn run(&mut self, noun: usize, verb: usize) -> usize {
        self.memory[1] = noun;
        self.memory[2] = verb;
        self.step(0);
        self.memory[0]
    }

    pub fn reset(&mut self) {
        self.memory = self.code.clone();
    }

    fn step(&mut self, pointer: usize) {
        match self.instruction(pointer) {
            ExitCode::Continue => self.step(pointer + 4),
            ExitCode::Halt => {}
        }
    }

    fn instruction(&mut self, pointer: usize) -> ExitCode {
        let opcode = self.memory[pointer];

        if opcode == 99 {
            return ExitCode::Halt;
        }

        let left_pointer = self.memory[pointer + 1];
        let left = self.memory[left_pointer];

        let right_pointer = self.memory[pointer + 2];
        let right = self.memory[right_pointer];

        let result_pointer = self.memory[pointer + 3];

        self.memory[result_pointer] = match opcode {
            1 => left + right,
            2 => left * right,
            _ => panic!("unknown opcode: {}", opcode),
        };

        ExitCode::Continue
    }
}

impl From<String> for Program {
    fn from(string: String) -> Self {
        let code: Vec<usize> = string
            .split(',')
            .map(|x| usize::from_str_radix(x, 10).expect("error converting input"))
            .collect();

        Self {
            code: code.clone(),
            memory: code,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Program;

    #[test]
    fn part_one() {
        let mut program = Program::from(String::from("1,0,0,0,99"));
        program.run(0, 0);
        assert_eq!(program.memory, [2, 0, 0, 0, 99]);

        let mut program = Program::from(String::from("2,3,0,3,99"));
        program.run(3, 0);
        assert_eq!(program.memory, [2, 3, 0, 6, 99]);

        let mut program = Program::from(String::from("2,4,4,5,99,0"));
        program.run(4, 4);
        assert_eq!(program.memory, [2, 4, 4, 5, 99, 9801]);

        let mut program = Program::from(String::from("1,1,1,4,99,5,6,0,99"));
        program.run(1, 1);
        assert_eq!(program.memory, [30, 1, 1, 4, 2, 5, 6, 0, 99]);
    }
}