loading...
Cover image for Advent of Code 2019 Solution Megathread - Day 2: 1202 Program Alarm

Advent of Code 2019 Solution Megathread - Day 2: 1202 Program Alarm

jbristow profile image Jon Bristow Updated on ・2 min read

Day 2 is in the books! And surprisingly, we're into pseudo-interpreter territory already!

Day 2 - The Problem

We need to slingshot ourselves around the moon, but the computer that calculates our trajectory has sadly exploded. Given our current data and the specs for that machine, we need to build ourselves a new IntCode interpreter.

It's surprising to me to see a psuedo-assembly converter so early in the Advent of Code, but this one turned out to be vaguely straightforward. Most of my personal problems stemmed from input validation. (If you're a newbie, let me assure you that input validation is almost always something that will slow you down. This goes triply for anyone learning a new language!)

Part 2 luckily doesn't require a whole lot of extra logic, but it has a bit of "optimization" and "compartmentalization" to keep tabs on.

Ongoing Meta

Dev.to List of Leaderboards

If you were part of Ryan Palo's leaderboard last year, you're still a member of that!

If you want me to add your leaderboard code to this page, reply to one of these posts and/or send me a DM containing your code and any theming or notes you’d like me to add. (You can find your private leaderboard code on your "Private Leaderboard" page.)

I'll edit in any leaderboards that people want to post, along with any description for the kinds of people you want to have on it. (My leaderboard is being used as my office's leaderboard.) And if I get something wrong, please call me out or message me and I’ll fix it ASAP.

There's no limit to the number of leaderboards you can join, so there's no problem belonging to a "Beginner" and a language specific one if you want.

Neat Statistics

I'm planning on adding some statistics, but other than "what languages did we see yesterday" does anyone have any ideas?

Discussion

pic
Editor guide
Collapse
aspittel profile image
Ali Spittel

I struggled with reading comprehension tonight 🤦🏼‍♀️

def calculate(num1, num2, nums):
    nums[1] = num1
    nums[2] = num2
    idx = 0
    while nums[idx] != 99:
        num = nums[idx]
        val1 = nums[nums[idx + 1]]
        val2 = nums[nums[idx + 2]]
        idx3 = nums[idx + 3]
        if num == 1:
            nums[idx3] = val1 + val2
        elif num == 2:
            nums[idx3] = val1 * val2
        idx += 4
    return nums[0]


with open("input.txt") as _file:
    for line in _file:
        input_values = [int(num) for num in line.split(",")]
        # part 1
        print(calculate(12, 2, input_values[:]))

        # part 2
        GOAL = 19690720
        for i in range(100):
            for j in range(100):
                if calculate(i, j, input_values[:]) == GOAL:
                    print(100 * i + j) 
                    break
Collapse
coolshaurya profile image
Shaurya Shubham

Yeah, the second part's wording was really confusing to me.

Collapse
jbristow profile image
Jon Bristow Author

Me too! I spent a good couple minutes trying to figure out why the sum of their test opcode didn't match the answer... 😭

Collapse
strahlistvan profile image
Stráhl István

Thank you! It really helps me to understand the second part.

Collapse
jojonarte profile image
Jojo Narte

My solution in JS.

const operations = {
  1: (inputArray, pos1, pos2, resultPos) => inputArray[inputArray[resultPos]] = inputArray[inputArray[pos1]] + inputArray[inputArray[pos2]],
  2: (inputArray, pos1, pos2, resultPos) => inputArray[inputArray[resultPos]] = inputArray[inputArray[pos1]] * inputArray[inputArray[pos2]],
};

const part1Solution = (inputArray, index = 0) => {
  const operation = inputArray[index];
  if (operation === 99) {
    return inputArray[0];
  }

  if (operation === 1 || operation === 2) {
    operations[operation](inputArray, index + 1, index + 2, index + 3)
  } else {
    throw new Error('Something went wrong!');
  }

  return part1Solution(inputArray, index + 4);
};

const part2Solution = (inputArray, targetValue) => {
  for (let i = 0; i <= 99; i ++) {
    for (let j = 0; j <= 99; j++) {
      const newArr = [...inputArray];
      newArr[1] = i;
      newArr[2] = j;
      const currentResult = part1Solution(newArr);
      console.log('CURRENT VALUE', currentResult);

      if (currentResult === targetValue) {
        return 100 * i + j;
      }
    }
  }

  throw new Error('Value not found');
};
Collapse
neilgall profile image
Neil Gall

In past Advent of Codes I've belligerently tried to write these machine simulators in Haskell or pure functional Kotlin or something else completely inappropriate. Maybe it's a sign of maturity that this year I've done it in C.

It's been a while since I've written C. The purity and simplicity is refreshing.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

typedef unsigned int opcode;

struct program {
    size_t size;
    opcode base[];
};

size_t program_size(size_t n) {
    return sizeof(size_t) + sizeof(opcode) * n;
}

struct program *load_program(char *filename) {
    size_t size = 100;
    struct program *program = (struct program *)malloc(program_size(size));
    size_t pos = 0;
    opcode cur = 0;
    FILE *f = fopen(filename, "rt");
    for (;;) {
        int c = fgetc(f);
        if (c == EOF || c == ',') {
            if (pos == size) {
                size *= 2;
                program = (struct program *)realloc(program, program_size(size));
            }
            program->base[pos++] = cur;
            cur = 0;
        } else if ('0' <= c && c <= '9') {
            cur = (cur * 10) + (c - '0');
        }
        if (c == EOF) break;
    }
    fclose(f);
    program->size = pos;
    return program;
}

struct program *copy_program(struct program *program) {
    size_t size = program_size(program->size);
    struct program *copy = (struct program *)malloc(size);
    memcpy(copy, program, size);
    return copy;
}

int read_program(struct program *program, size_t pos, opcode *x) {
    if (pos >= program->size) {
        return 1;
    }
    *x = program->base[pos];
    return 0;
}

int write_program(struct program *program, size_t pos, opcode value) {
    if (pos >= program->size) {
        return 1;
    }
    program->base[pos] = value;
    return 0;
}

void print_program(struct program *program) {
    printf("%u", program->base[0]);
    for (int i = 1; i < program->size; ++i) {
        printf(",%u", program->base[i]);
    }
    printf("\n");
}

int run_program(struct program *program, int debug) {
    size_t pc = 0;
    opcode i;
    while (read_program(program, pc, &i) == 0 && i != 99) {
        opcode x, y, z;
        if (read_program(program, pc+1, &x) != 0) return 1;
        if (read_program(program, x,    &x) != 0) return 1;
        if (read_program(program, pc+2, &y) != 0) return 1;
        if (read_program(program, y,    &y) != 0) return 1;
        if (read_program(program, pc+3, &z) != 0) return 1;
        if (debug) printf("pc=%u i=%u x=%u y=%u z=%u\n", pc, i, x, y, z);
        switch (i) {
            case 1: 
                if (write_program(program, z, x + y) != 0) return 1;
                break;
            case 2:
                if (write_program(program, z, x * y) != 0) return 1;
                break;
            default:
                return 1;
        }
        if (debug) print_program(program);
        pc += 4;
    }
    return 0;
}

void modify_program(struct program *program) {
    program->base[1] = 12;
    program->base[2] = 2;
}

void part1(struct program *original) {
    printf("Part 1\n");
    struct program *program = copy_program(original);
    modify_program(program);
    run_program(program, 0);
    print_program(program);
    free(program);  
}

void part2(struct program *original) {
    opcode noun = 0;
    opcode verb = 0;
    int result = 0;
    while (noun < 100 && verb < 100) {
        struct program *program = copy_program(original);
        write_program(program, 1, noun);
        write_program(program, 2, verb);
        int result = run_program(program, 0) == 0 && program->base[0] == 19690720;
        free(program);

        if (result) {
            break;
        }

        if (++noun > 99) {
            noun = 0;
            ++verb;
        }
    }
    printf("Part 2\nnoun = %u\nverb = %u\nresult = %u\n", noun, verb, 100*noun+verb);
}

static struct program test_program = {
    .size = 12,
    .base = { 1,9,10,3,2,3,11,0,99,30,40,50 }
};

int main(int argc, char **argv) {
    struct program *program = (argc < 2) ? load_program("input.txt") : &test_program;
    part1(program);
    part2(program);

    if (program != &test_program) {
        free(program);
    }
    return 0;
}
Collapse
jbristow profile image
Jon Bristow Author

Funny, I think they're harder to write initially in a functional language, but easier to modify and extend in later questions.

Collapse
neilgall profile image
Neil Gall

Extending to part 2 was easy enough. But the description today made it clear more is coming so I can't wait to find out!

Collapse
supriyasrivatsa profile image
Supriya Srivatsa

Some Kotlin code :)

fun main() {
    val input = readDayInputAsString(2).split(",").map { it.toInt() }
    val noun = 12
    val verb = 2

    println(solvePart1(input, noun, verb))  //5434663
    println(solvePart2(input, noun, verb))  //4559
}

private fun solvePart1(programInput: List<Int>, noun: Int, verb: Int) : Int {
    val input = programInput.toMutableList()
    input[1] = noun
    input[2] = verb
    for(i in input.indices step 4) {
        when(input[i]) {
            99 -> return input[0]
            1 -> input[input[i+3]] = input[input[i+1]] + input[input[i+2]]
            2 -> input[input[i+3]] = input[input[i+1]] * input[input[i+2]]
        }
    }
    return input[0]
}

private fun solvePart2(programInput: List<Int>, noun: Int, verb: Int) : Int {
    for(i in 0..99) {
        for(j in 0..99) {
            if(solvePart1(programInput, i, j) == 19690720)
                return 100 * i + j
        }
    }
    return 100 * noun + verb
}

On github: github.com/sup95/AdventOfCode-19/b...

Collapse
katafrakt profile image
Paweł Świątkowski

I can't believe no one has posted a solution in Janet yet! Oh wait, no, I totally believe it. It was also my first attempt in this language. I've been looking at it for some time already but only today I decided to give it a shot. It basically feels like a imperativ-ish LISP.

(def input "1,0,0,the rest of your input...")

(defn run-prog [noun verb]
  (def codes (map (fn [x] (scan-number x)) (string/split "," input)))
  (put codes 1 noun)
  (put codes 2 verb)

  (var curpos 0)
  (var curinstr (get codes curpos))
  (while (not (= curinstr 99))
    (def elem1 (get codes (+ curpos 1)))
    (def elem2 (get codes (+ curpos 2)))
    (def elem3 (get codes (+ curpos 3)))

    (if (= curinstr 1)
      (put codes elem3 (+ (get codes elem1) (get codes elem2))))

    (if (= curinstr 2)
      (put codes elem3 (* (get codes elem1) (get codes elem2))))

    (set curpos (+ curpos 4))
    (set curinstr (get codes curpos)))
  (get codes 0))

(print (string/format "%d" (run-prog 12 2)))

(loop [noun :range [0 99]]
  (loop [verb :range [0 99]]
    (def res (run-prog noun verb))
    (if (= res 19690720)
      (print (string/format "%d" (+ (* 100 noun) verb))))))
Collapse
lindakatcodes profile image
Linda Thompson

JavaScript checking in! I think it'll be interesting, seeing how we re-use this in future challenges. It did take me reading the end of part 2 a number of times before I understood what I was looking for! :)

I also feel like there should be a better way to process the second part...I saw folks on the subreddit talking about just changing the noun value until it's as high as can be while still below the desired output, then changing the verb, but it seems maybe there's unforeseen issues with that? I don't know, everyone I've seen so far is just nesting for loops so I'm not that worried about it. :)

// copy of initial input, so we can reset properly
let inputCopy = [...input];

// noun - input for address 1; verb - input for address 2
let noun = 12;
let verb = 2;

// for part 2 - desired output to match - output is final value at address 0 when program is done
const desiredOutput = 19690720;
// opcode 1 - get values at position 1&2 right after code, add together, store in position 3
// opcode 2 - get values at position 1&2 right after code, multiply, store in position 3
// opcode 99 - stop program
function intCode (op, a, b, c) {
  let valA = inputCopy[a];
  let valB = inputCopy[b];

  if (op === 1) {
    inputCopy[c] = valA + valB;
  } else if (op === 2) {
    inputCopy[c] = valA * valB;
  }
}

// run through memory input, following instructions until 99 is hit
function runProgram() {
  for (let i = 0; i < inputCopy.length; i += 4) {
    if (inputCopy[i] === 99) {
      break;
    }
    intCode(inputCopy[i], inputCopy[i+1], inputCopy[i+2], inputCopy[i+3]);
  }
}

// for part 1 - insert noun & verb provided
inputCopy[1] = noun;
inputCopy[2] = verb;

runProgram();
console.log(`Part 1: position 0 value is ${inputCopy[0]}`);

// part 2 - test different values for noun & verb, insert into memory, run program - when desired output is matched, log noun & verb used & end cycle

for (let n = 0; n < 100; n++) {
  noun = n;
  let found = false;
  for (let v = 0; v < 100; v++) {
    verb = v;

    // reset copy to initial input, then replace noun & verb
    inputCopy = [...input];
    inputCopy[1] = noun;
    inputCopy[2] = verb;

    runProgram();
    let currentOutput = inputCopy[0];

    if (currentOutput === desiredOutput) {
      found = true;
      break;
    }
  }
  if (found) {
    break;
  }
}

console.log(`desired noun and verb are ${noun} & ${verb}; output value is ${inputCopy[0]}`);
console.log(`Part 2 - computed value is ${100 * noun + verb}`);
Collapse
jakcharvat profile image
Jakub Charvat

Here's my Python solution - nothing special or well optimised, but it works:

def puzzle_one():
    with open('inputs/day_2.txt') as file: 
        input = list(map(lambda a: int(a), file.read().split(',')))

    opcode, index = int(input[0]), 0
    while opcode != 99:
        if opcode == 1:
            sum = input[input[index + 1]] + input[input[index + 2]]
            input[input[index + 3]] = sum
        elif opcode == 2:
            product = input[input[index + 1]] * input[input[index + 2]]
            input[input[index + 3]] = product
        elif opcode != 99:
            print('Something went wrong')

        index += 4
        opcode = input[index]

    print(f'Puzzle 1 - {input[0]}')

def puzzle_two():

    goal = 19690720

    with open('inputs/day_2.txt') as file:
        input = list(map(lambda a: int(a), file.read().split(',')))

    found = False
    for noun in range(100):
        for verb in range(100):
            memory = input[:]
            memory[1] = noun
            memory[2] = verb

            opcode, index = int(input[0]), 0
            while opcode != 99:
                if opcode == 1:
                    sum = memory[memory[index + 1]] + memory[memory[index + 2]]
                    memory[memory[index + 3]] = sum
                elif opcode == 2:
                    product = memory[memory[index + 1]] * memory[memory[index + 2]]
                    memory[memory[index + 3]] = product
                elif opcode != 99:
                    print('Something went wrong')

                index += 4
                opcode = memory[index]

            output = memory[0]

            if output == goal:
                final_noun = noun
                final_verb = verb
                found = True
                break
        if found == True:
            break
    print(f'Puzzle 2 - {100 * final_noun + final_verb}')

puzzle_one()
puzzle_two()
Collapse
mellen profile image
Matt Ellen

In the browser!

function process(one, two)
{
    let pretext = document.getElementsByTagName('pre')[0].innerHTML;
    let instructions = pretext.split(',').map(i => parseInt(i, 10));
    instructions[1] = one;
    instructions[2] = two;
    for(let i = 0; i < instructions.length; i += 4)
    {
    let inst = instructions[i];
    if(inst == 99)
    {
        break;
    }

    let answerPos = instructions[i+3];
    let ai = instructions[i+1];
    let bi = instructions[i+2];

    if(inst == 1)
    {
        instructions[answerPos] = instructions[ai] + instructions[bi];
    }
    else if(inst == 2)
    {
        instructions[answerPos] = instructions[ai] * instructions[bi];
    }
    }

    return instructions[0];
}

/* part 2 */
let done = false;
for(let a = 0; a < 100 && !done; a++)
{
  for(let b = 0; b < 100; b++)
  {
    let n = process(a, b);
    if(n == 19690720)
    {
      console.log(a, b)
      done = true;
      break;
    }
  }
}
Collapse
rpalo profile image
Ryan Palo

Here's my Rust code. I was lucky that I caught that bit at the very end of the instructions about setting the initial values. Otherwise I probably would have spiraled trying to figure out why my answer to Part 1 was wrong.

Now I just need to refactor this out to make it easy to extend for future days!

/// Day 2: 1202 Program Alarm
/// 
/// Create an "Intcode" computer that can calculate a gravity slingshot

use std::fs;

/// Parses the input.  Expects a single line of integers separated by
/// commas
fn parse_input() -> Vec<usize> {
    let text: String = fs::read_to_string("data/day2.txt").unwrap();
    let cleaned = text.trim();
    cleaned.split(",").map( |c| c.parse().unwrap()).collect()
}

/// An Intcode Interpreter is a simple virtual machine that uses opcodes
/// to modify its internal memory
struct IntcodeInterpreter {
    ints: Vec<usize>,
    ip: usize,
}

impl IntcodeInterpreter {
    pub fn new(ints: Vec<usize>) -> Self {
        Self { ints, ip: 0}
    }

    /// Sets a memory address to a value
    pub fn set(&mut self, position: usize, value: usize) {
        self.ints[position] = value;
    }

    /// Reads from a memory address
    pub fn get(&self, position: usize) -> usize {
        self.ints[position]
    }

    /// Runs the program in memory until the stopcode (99) is reached
    /// (To be refactored and generalized)
    pub fn run(&mut self) {
        while self.ints[self.ip] != 99 {
            let opcode = self.ints[self.ip];
            let in1 = self.ints[self.ip + 1];
            let in2 = self.ints[self.ip + 2];
            let out = self.ints[self.ip + 3];

            if opcode == 1 {
                self.ints[out] = self.ints[in1] + self.ints[in2];
            } else if opcode == 2 {
                self.ints[out] = self.ints[in1] * self.ints[in2];
            } else {
                panic!("Unrecognized opcode {}!", opcode);
            }
            self.ip = (self.ip + 4) % self.ints.len();
        }
    }
}

/// Given a desired output, hunts through the possible values of position
/// 1 and 2 (termed "noun" and "verb") by brute force until the output
/// is found.
fn find_output(output: usize, ints: Vec<usize>) -> (usize, usize) {
    for noun in 0..=99 {
        for verb in 0..=99 {
            let mut interpreter = IntcodeInterpreter::new(ints.clone());
            interpreter.set(1, noun);
            interpreter.set(2, verb);
            interpreter.run();
            if interpreter.get(0) == output {
                return (noun, verb);
            }
        }
    }

    panic!("Couldn't find output!");
}

pub fn run() {
    let ints = parse_input();

    println!("Part 1:");
    let mut interpreter = IntcodeInterpreter::new(ints.clone());
    interpreter.set(1, 12);
    interpreter.set(2, 2);
    interpreter.run();
    println!("After running, position 0 is: {}", interpreter.get(0));

    println!("Part 2:");
    let (noun, verb) = find_output(19690720, ints.clone());
    println!("Noun: {}, Verb: {}", noun, verb);
    println!("Secret code is: {}{}", noun, verb);

}
Collapse
yordiverkroost profile image
Yordi Verkroost

Pretty rough assignment on day two already, but got it working in the end! I've solved it in Elixir. Here's my solution for part two:

defmodule Aoc19.Day2b do
  @moduledoc false

  alias Aoc19.Utils.Common

  @add 1
  @multiply 2
  @halt 99
  @opcode [@add, @multiply, @halt]

  def start(input_location) do
    opcode =
      input_location
      |> Common.read_numbers(",")
      |> verify()

    try do
      for i <- 1..100 do
        for j <- 1..100 do
          _ =
            case result(opcode, i, j) do
              19_690_720 ->
                throw(100 * i + j)

              _ ->
                nil
            end
        end
      end
    catch
      result -> result
    end
  end

  defp result(opcode, noun, verb) do
    opcode = replace(opcode, noun, verb)

    opcode
    |> intcode(opcode, 0)
    |> Enum.at(0)
  end

  defp verify([x | _] = opcode) when x in @opcode, do: opcode

  defp replace(opcode, noun, verb) do
    opcode
    |> List.update_at(1, fn _ -> noun end)
    |> List.update_at(2, fn _ -> verb end)
  end

  defp intcode([@halt | _], opcode, _), do: opcode

  defp intcode([@add, int1, int2, result | _], opcode, index) do
    opcode =
      List.update_at(opcode, result, fn _ ->
        Enum.at(opcode, int1) + Enum.at(opcode, int2)
      end)

    index = index + 4
    {_, rest} = Enum.split(opcode, index)

    intcode(rest, opcode, index)
  end

  defp intcode([@multiply, int1, int2, result | _], opcode, index) do
    opcode =
      List.update_at(opcode, result, fn _ ->
        Enum.at(opcode, int1) * Enum.at(opcode, int2)
      end)

    index = index + 4
    {_, rest} = Enum.split(opcode, index)

    intcode(rest, opcode, index)
  end
end

Check out part one here

Collapse
rizzu26 profile image
Rizwan

It took more time than I expected but finally done with it. I actually started Day 1 today as well.

Here is my solution in swift. Incase anyone would like followup code can be found here in Github

/// --- Day 2: 1202 Program Alarm ---
func computeIntCode(_ input: [Int]) -> Int {
    var numbers = input

    func add(_ aPosition: Int, _ bPosistion: Int) -> Int {
        return numbers[aPosition] + numbers[bPosistion]
    }

    func multiply(_ aPosition: Int, _ bPosistion: Int) -> Int {
        return numbers[aPosition] * numbers[bPosistion]
    }

    func compute(integers:[Int]) {
        let opcode = integers[0]
           switch opcode {
           case 1:
               let result = add(integers[1], integers[2])
               numbers[integers[3]] = result
               //print(numbers)
               break
           case 2:
               let result = multiply(integers[1], integers[2])
               numbers[integers[3]] = result
               //print(numbers)
               break
           case 99:
               break
           default:
               break
           }
    }

    var index = 0
    while true {
        let number = numbers[index]
        if number == 1 || number == 2 {
            compute(integers: Array(numbers[index...index+4]))
            index = index + 4
        }
        else if number == 99 {
            break
        }
    }
    //print(numbers)
    return numbers[0]
}

func computeIntCode(_ input:[Int], _ noun: Int, _ verb: Int) -> Int {
    var input = input
    input[1] = noun
    input[2] = verb
    return computeIntCode(input)
}

let input = """
    1,0,0,3,1,1,2,3,1,3,4,3,1,5,0,3,2,1,10,19,2,9,19,23,1,9,23,27,2,27,9,31,1,31,5,35,2,35,9,39,1,39,10,43,2,43,13,47,1,47,6,51,2,51,10,55,1,9,55,59,2,6,59,63,1,63,6,67,1,67,10,71,1,71,10,75,2,9,75,79,1,5,79,83,2,9,83,87,1,87,9,91,2,91,13,95,1,95,9,99,1,99,6,103,2,103,6,107,1,107,5,111,1,13,111,115,2,115,6,119,1,119,5,123,1,2,123,127,1,6,127,0,99,2,14,0,0
    """
let numbers = input.components(separatedBy: ",").compactMap{Int($0)}

func partOne() {
    dump(computeIntCode(numbers,12,2))
}

func partTwo() {
    for i in 0..<99 {
        for j in 0..<99 {
            if computeIntCode(numbers,i,j) == 19690720 {
                print("noun: \(i) \n verb: \(j)")
                dump(100 * i + j)
                return
            }
        }
    }
}

partOne()
partTwo()
Collapse
ballpointcarrot profile image
Christopher Kruse

Back again with more Clojure.

My favorite part of this is how the actions get selected. the get-action function actually returns the function used for handling the inputs (where 99 returns a function that, regardless of input, returns "stop"). Then, that function is used with the apply function inside calculate to actually pass the arguments to that function.

I'm sure there should be a better way of handling the brute force handling of part 2, but for now, it's just a poor man's nested for loop implemented using atoms.

(ns aoc2019.day2
  (:require [clojure.string :as st]))

(defn get-action
  "Selects an action from the available opcodes"
  [action]
  (condp = action
    1 +
    2 *
    99 (constantly "stop")))

(defn parse-input
  "Converts input into atom holding instruction integers."
  [input]
  (map #(Integer/parseInt %) (st/split (st/trim-newline input) #",")))

(defn initial-adjustments
  [instructions noun verb]
  (-> instructions
      (assoc 1 noun)
      (assoc 2 verb)))

(defn calculate
  "Read opcodes, insert required values, and read position 0 when complete."
  [input noun verb]
  (loop [instructions (initial-adjustments (vec (parse-input input)) noun verb)
         cursor 0]
    (let [[action pos1 pos2 result-pos] (take 4 (drop cursor instructions))
          result (apply (get-action action) [(get instructions pos1) (get instructions pos2)])]
      (if (= result "stop")
        (first instructions)
        (recur (assoc instructions result-pos result) (+ 4 cursor))))))

(defn p2019-02-part1
  [input]
  (calculate input 12 2))

(defn p2019-02-part2
  "Using the calculator from part 1, determine the proper inputs for our expected value."
  [input]
  (let [expected-result 19690720
        noun (atom 0)
        verb (atom 0)]
    (while (not= expected-result (calculate input @noun @verb))
      (swap! verb inc)
      (if (= @verb 100)
        (do
          (swap! noun inc)
          (reset! verb 0))))
    (+ @verb (* 100 @noun))))

(defn run
  "Runs the Day 2 solutions."
  []
  (let [input (slurp "inputs/2019-02-input")]
    (println (str "Part 1: " (p2019-02-part1 input)))
    (println (str "Part 2: " (p2019-02-part2 input)))))
Collapse
coolshaurya profile image
Shaurya Shubham

My solution in Rust

fn part_a(mut input: Vec<u32>) -> u32 {
    input[1] = 12;
    input[2] = 2;

    let mut i: usize = 0;
    while i < input.len() {
        if i % 4 == 0 {
            let opcode = input[i];
            if opcode == 99 {
                break;
            }
            let index_1 = input[i + 1] as usize;
            let index_2 = input[i + 2] as usize;
            let index_3 = input[i + 3] as usize;

            if opcode == 1 {
                input[index_3] = input[index_1] + input[index_2];
            } else if opcode == 2 {
                input[index_3] = input[index_1] * input[index_2];
            }
        }
        i = i + 1;
    }

    input[0]
}

fn part_b(input: Vec<u32>) -> u32 {
    let mut i = 0;
    let mut j = 0;
    while i < 100 {
        let mut input = input.clone();

        if exec_intcode_program(input, i, j) == 19690720 {
            return 100 * i + j;
            break;
        }

        if j == 99 {
            i = i + 1;
            j = 0;
        }
        j = j + 1;
    }

    0
}
fn exec_intcode_program(input: Vec<u32>, addl_inp_1: u32, addl_inp_2: u32) -> u32 {
    let mut input = input.clone();

    input[1] = addl_inp_1;
    input[2] = addl_inp_2;

    let mut i: usize = 0;
    while i < input.len() {
        if i % 4 == 0 {
            let opcode = input[i];
            if opcode == 99 {
                break;
            }
            let index_1 = input[i + 1] as usize;
            let index_2 = input[i + 2] as usize;
            let index_3 = input[i + 3] as usize;

            if opcode == 1 {
                input[index_3] = input[index_1] + input[index_2];
            } else if opcode == 2 {
                input[index_3] = input[index_1] * input[index_2];
            }
        }
        i = i + 1;
    }

    input[0]
}
Collapse
jbristow profile image
Jon Bristow Author

My kotlin solution:

object Day02 {

    private const val FILENAME = "src/main/resources/day02.txt"

    fun handleOpcode(offset: Int, intList: Either<Array<Int>, Array<Int>>): Either<Array<Int>, Array<Int>> =
        intList.flatMap {
            val opcodeChunk = it.drop(offset).take(4)

            when (opcodeChunk[0]) {
                1 -> {
                    it[opcodeChunk[3]] = it[opcodeChunk[1]] + it[opcodeChunk[2]]
                    it.right()
                }
                2 -> {
                    it[opcodeChunk[3]] = it[opcodeChunk[1]] * it[opcodeChunk[2]]
                    it.right()
                }
                99 -> it.left()
                else -> throw Error("Unknown opcode: ${opcodeChunk[0]}")
            }
        }


    fun part1() = Files.readString(Paths.get(FILENAME))
        .trim()
        .prepInput().let {
            it[1] = 12
            it[2] = 2
            it
        }.operate()[0]
        .toString()

    fun part2(): String {
        val input = Files.readString(Paths.get(FILENAME))
            .trim().prepInput()

        return (0..99).fold(Unit.right() as Either<Pair<Int, Int>, Unit>) { foundSoFar, noun ->
            foundSoFar.flatMap {
                val found = (0..99).find { verb ->
                    val inputCopy = input.copyOf()
                    inputCopy[1] = noun
                    inputCopy[2] = verb
                    inputCopy.operate()[0] == 19690720
                }
                if (found == null) {
                    foundSoFar
                } else {
                    (noun to found).left()
                }
            }
        }.fold({ (noun, verb) ->
            "%02d%02d".format(noun, verb)
        }, { throw Error("No match found.") })
    }
}

fun String.prepInput() = split(",").map { it.toInt() }.toTypedArray()

fun Array<Int>.operate() =
    this.let {
        (0..this.size / 4).map { it * 4 }
            .fold(this.right() as Either<Array<Int>, Array<Int>>) { intArr, offset ->
                handleOpcode(offset, intArr)
            }.fold({ it }, { it })
    }

fun main() {
    println("Part 1: ${Day02.part1()}")
    println("Part 2: ${Day02.part2()}")
}

Collapse
lindakatcodes profile image
Linda Thompson

Also super stoked that the poem I wrote for day 1 was picked as the first winner! So my comment on the megathread has a little silver medal next to it. :) For not having written any sort of fun fiction in years, I'm really excited they liked it enough to reward it!

Screenshot of award comment

They sent me a fun little image when they commented on it, too -
Elf being given a gold star by Santa, in a Mario themed setting

Collapse
jbristow profile image
Jon Bristow Author

Congratulations! I love the secondary artifacts and self-imposed additional challenges that people do for this. People seem to get more creative every year!

Collapse
noakpalander profile image
Noak Palander

A bit late to the party, got my c++17 code working however

#include <fstream>
#include <vector>
#include <string>
#include <optional>
#include <optional>
#include <iostream>
#include <cmath>
#include <sstream>

std::optional<std::vector<unsigned int>> ReadFile(const std::string& filename) {
std::ifstream reader(filename.c_str());

    if (reader) {
        std::string data;
        reader >> data;

        std::stringstream ss(data);

        std::vector<unsigned int> out;
        for (unsigned int val; ss >> val;) {
            out.emplace_back(val);
            if (ss.peek() == ',')
                ss.ignore();
        }

        return out;
    }

    return {};
}

unsigned int Calculate(unsigned int first, unsigned int second, std::vector<unsigned int> data) {
    // Set initial values
    data[1] = first;
    data[2] = second;

    for (unsigned int i = 0; i < data.size(); i += 4) {
        const unsigned int FIRST = data[i + 1];
        const unsigned int SECOND = data[i + 2];
        const unsigned int LOCATION = data[i + 3];


        switch (data[i]) {
            // Addition
            case 1:
                data[LOCATION] = data[FIRST] + data[SECOND];
                break;

            // Multiplication
            case 2:
                data[LOCATION] = data[FIRST] * data[SECOND];
                break;

            // Terminate
            case 99:
                return data[0];
                break;

            default:
                break;
        }
    }

    return data[0];
}


int main() {
    if (auto data = ReadFile("puzzle_input"); data.has_value()) {
        /* Part one */
        unsigned int ans1 = Calculate(12, 2, data.value());
        std::cout << "The answer to part_1 is " << ans1 << "\n";

        /* Part 2 */
        // Reset data set
        data.value() = ReadFile("puzzle_input").value();

        const unsigned int GOAL = 19690720;

        // 100*100 is enough iterations
        for (unsigned int noun = 0; noun < 100; noun++)
            for (unsigned int verb = 0; verb < 100; verb++)
                if (Calculate(noun, verb, data.value()) == GOAL)
                    std::cout << "\nThe answer to part_2 is " << 100 * noun + verb << "\n";
    }
    else
        std::cerr << "Failed to read puzzle_input!\n";

    return 0;
}
Collapse
thibpat profile image
Thibaut Patel

I got a couple of issues with types in JavaScript, but here is the solution:

Collapse
bretthancox profile image
bretthancox

I wrote my day 2 up here:

Day 2

Written in Clojure