DEV Community

Discussion on: Advent of Code 2019 Solution Megathread - Day 9: Sensor Boost

Collapse
 
nordfjord profile image
Einar Norðfjörð

JS Solution w/ generators again

I like being able to "plug in" the IO implementation at runtime with the yields, it's almost like algebraic effects in JS

const { createInterface } = require('readline')

const rl = createInterface({
  input: process.stdin,
  output: process.stdout
})

const question = str =>
  new Promise(res => {
    rl.question(str, res)
  })

const INSTRUCTIONS = {
  ADD: 1,
  MULT: 2,
  INPUT: 3,
  OUTPUT: 4,
  JUMP_IF_TRUE: 5,
  JUMP_IF_FALSE: 6,
  LESS_THAN: 7,
  EQUALS: 8,
  ADJUST_RELATIVE_BASE: 9,
  HALT: 99
}

function runProgram(instructions) {
  instructions = instructions.slice()

  return function* amplifier() {
    let lastOutput = null
    let relativeBase = 0
    for (let i = 0; i < instructions.length; ++i) {
      const instruction = instructions[i]
      const parsed = String(instruction)
        .padStart(5, '0')
        .split('')
      const getValue = (value, mode = '0') => {
        if (mode === '0') {
          return instructions[value] || 0
        } else if (mode === '1') {
          return value
        } else if (mode === '2') {
          return instructions[relativeBase + value] || 0
        }
      }
      const setValue = (index, value, mode = '0') => {
        if (mode === '0') {
          instructions[index] = value
        } else if (mode === '2') {
          instructions[relativeBase + index] = value
        }
      }
      const opCode = Number(parsed.slice(3).join(''))
      const modes = parsed.slice(0, 3)
      switch (opCode) {
        case INSTRUCTIONS.ADD: {
          const x = getValue(instructions[++i], modes[2])
          const y = getValue(instructions[++i], modes[1])
          setValue(instructions[++i], x + y, modes[0])
          break
        }
        case INSTRUCTIONS.MULT: {
          const x = getValue(instructions[++i], modes[2])
          const y = getValue(instructions[++i], modes[1])
          setValue(instructions[++i], x * y, modes[0])
          break
        }
        case INSTRUCTIONS.INPUT: {
          setValue(instructions[++i], yield { type: 'INPUT' }, modes[2])
          break
        }
        case INSTRUCTIONS.OUTPUT: {
          lastOutput = getValue(instructions[++i], modes[2])
          yield { type: 'OUTPUT', value: lastOutput }
          break
        }
        case INSTRUCTIONS.JUMP_IF_TRUE: {
          const compare = getValue(instructions[++i], modes[2])
          const jumpTo = getValue(instructions[++i], modes[1]) - 1
          if (compare != 0) {
            i = jumpTo
          }
          break
        }
        case INSTRUCTIONS.JUMP_IF_FALSE: {
          const compare = getValue(instructions[++i], modes[2])
          const jumpTo = getValue(instructions[++i], modes[1]) - 1
          if (compare == 0) {
            i = jumpTo
          }
          break
        }
        case INSTRUCTIONS.LESS_THAN: {
          const x = getValue(instructions[++i], modes[2])
          const y = getValue(instructions[++i], modes[1])
          setValue(instructions[++i], x < y ? 1 : 0, modes[0])
          break
        }
        case INSTRUCTIONS.EQUALS: {
          const x = getValue(instructions[++i], modes[2])
          const y = getValue(instructions[++i], modes[1])
          setValue(instructions[++i], x === y ? 1 : 0, modes[0])
          break
        }
        case INSTRUCTIONS.ADJUST_RELATIVE_BASE: {
          const adjustBy = getValue(instructions[++i], modes[2])
          relativeBase += adjustBy
          break
        }
        case INSTRUCTIONS.HALT:
          return lastOutput
      }
    }
  }
}

const runProgramWithIO = async program => {
  let input = undefined
  while (true) {
    const { value, done } = program.next(input)

    if (done) {
      return value
    }

    if (value.type === 'INPUT') {
      input = Number(await question('input : '))
      continue
    } else if (value.type === 'OUTPUT') {
      console.log('output:', value.value)
    }
  }
}

const input = require('fs')
  .readFileSync(require('path').resolve(__dirname, './input.txt'))
  .toString()

const instructions = input.split(',').map(Number)

runProgramWithIO(runProgram(instructions)())
  .then(final => console.log('final :', final))
  .then(() => process.exit())

Collapse
 
leonfedotov profile image
Leon Fedotov

Dope! Ive started doing this but it was taking me too long, checkout my solutions at github.com/LeonFedotov/advent-of-code