summaryrefslogtreecommitdiff
path: root/2019/rust/day02/src/main.rs
blob: 0d3362af168cef1412b130748b68a2c845675cea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use std::io::{self, BufRead};
use std::env;

// https://stackoverflow.com/q/37888042/remove-single-trailing-newline-from-string-without-cloning
fn trim_newline(s: &mut String) {
    if s.ends_with('\n') {
        s.pop();
        if s.ends_with('\r') {
            s.pop();
        }
    }
}

fn read_input() -> Vec<usize> {
    let stdin = io::stdin();

    // Far from neat, but gets the job done...
    stdin.lock().split(b',').map(|v| {
        let mut s = String::from_utf8(v.unwrap()).unwrap();
        trim_newline(&mut s);
        let u:u32 = s.parse().unwrap();
        u as usize
    }).collect()
}

fn restore_gravity_assist(window:&mut [usize], noun:usize, verb:usize) {
    window[0] = noun;
    window[1] = verb;
}

fn add(ip:usize, memory:&mut Vec<usize>) {
    let result = memory[ip + 3];
    let left = memory[ip + 1];
    let right = memory[ip + 2];
    memory[result] = memory[left] + memory[right];
}

fn mul(ip:usize, memory:&mut Vec<usize>) {
    let result = memory[ip + 3];
    let left = memory[ip + 1];
    let right = memory[ip + 2];
    memory[result] = memory[left] * memory[right];
}

fn intcode(mut memory:Vec<usize>) -> usize {
    let mut ip = 0;
    while ip < memory.len() {
        let op = memory[ip];
        match op {
            1 => { add(ip, &mut memory); ip += 4 },
            2 => { mul(ip, &mut memory); ip += 4 },
            99 => break,
            op => panic!("Invalid operation {}", op),
        }
    }
    memory[0]
}

fn first_puzzle(mut memory:Vec<usize>) -> usize {
    println!("No argument provided, hence attemping to solve first puzzle.");

    restore_gravity_assist(&mut memory[1..3], 12, 2);
    intcode(memory)
}

fn second_puzzle(desired:usize, mut memory:Vec<usize>) -> Option<usize> {
    println!("Desired output {} specified. Assuming second puzzle to search for it.", desired);
    for noun in 0..100 {
        for verb in 0..100 {
            restore_gravity_assist(&mut memory[1..3], noun, verb);
            if intcode(memory.clone()) == desired {
                return Some(100 * noun + verb);
            }
        }
    }

    None
}

fn main() {
    let memory = read_input();

    let needle = env::args().nth(1);
    let solution = match needle {
        None    => Some(first_puzzle(memory)),
        Some(n) => second_puzzle(n.parse().unwrap_or(0), memory),
    };

    match solution {
        Some(s) => println!("Solution: {}.", s),
        _       => println!("No solution found."),
    }
}