Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- module Intcode
- using OffsetArrays
- export parseInput, Program, runProgram, newProgram
- const parseInput(i) = split(i, ",") |>
- lines -> map(x -> parse(Int, x), lines) |>
- x -> OffsetArray(x, -1)
- mutable struct Program
- memory :: OffsetArrays.OffsetArray{Int64,1,Array{Int64,1}}
- address :: Int
- input :: Array{Int, 1}
- output :: Array{Int, 1}
- relativeBase :: Int
- halted :: Bool
- paused :: Bool
- stopOnOutput :: Bool
- end
- function parseOpcode(opcode::Int)
- if opcode <= 10 || opcode == 99
- return (opcode, (0, 0, 0))
- end
- digs = digits(opcode; pad = 5)
- if [digs[1], digs[2]] == [9,9]
- return (99, (digs[3], digs[4], digs[5]))
- end
- return (digs[1], (digs[3], digs[4], digs[5]))
- end
- function accessMemory(program::Program, address::Int)
- diff = address-length(program.memory)+1
- if diff <= 0
- return program.memory[address]
- else
- resize!(parent(program.memory), length(program.memory)+(diff))
- return 0
- end
- end
- function applyMode(program::Program, mode::Int, value::Int, output=false)
- if mode == 0
- return !output ? accessMemory(program, value) : value
- elseif mode == 1
- return value
- elseif mode == 2
- return !output ? accessMemory(program, value+program.relativeBase) : value+program.relativeBase
- end
- end
- function parseInstructions(program::Program, opcode::Int, modes::Tuple{Int, Int, Int})
- if opcode == 99
- return (0, 0, 0)
- elseif opcode == 3
- return (0, 0, applyMode(program, modes[1], program.memory[program.address+1], true))
- elseif opcode in [4, 9]
- return (applyMode(program, modes[1], program.memory[program.address+1], false), 0, 0)
- else
- return map(((i, mode),) -> applyMode(program, mode, program.memory[program.address+i], i == 3), enumerate(modes))
- end
- end
- const operations = Dict(
- 1 => (program, input, output) -> begin
- program.memory[output] = input[1] + input[2]
- program.address += 4
- end,
- 2 => (program, input, output) -> begin
- program.memory[output] = input[1] * input[2]
- program.address += 4
- end,
- 3 => (program, input, output) -> begin
- program.memory[output] = popfirst!(program.input)
- program.address += 2
- end,
- 4 => (program, input, output) -> begin
- push!(program.output, input[1])
- program.address += 2
- if program.stopOnOutput
- program.paused == true
- end
- end,
- 5 => (program, input, output) -> begin
- program.address = input[1] != 0 ? input[2] : program.address + 3
- end,
- 6 => (program, input, output) -> begin
- program.address = input[1] == 0 ? input[2] : program.address + 3
- end,
- 7 => (program, input, output) -> begin
- program.memory[output] = input[1] < input[2] ? 1 : 0
- program.address += 4
- end,
- 8 => (program, input, output) -> begin
- program.memory[output] = input[1] == input[2] ? 1 : 0
- program.address += 4
- end,
- 9 => (program, input, output) -> begin
- program.relativeBase += input[1]
- program.address += 2
- end,
- 99 => (program, input, output) -> program.halted = true
- )
- function doOperation(program::Program)
- memoryValue = accessMemory(program, program.address)
- opcode, modes = parseOpcode(memoryValue)
- instructions = parseInstructions(program, opcode, modes)
- input = instructions[1:2]
- outputAddress = instructions[end]
- accessMemory(program, outputAddress)
- #println("#", program.address, " " ,opcode, " ", modes, " ", memoryValue, " ", (instructions[1], instructions[2]) , " ", isnothing(outputAddress) ? 0 : outputAddress)
- operations[opcode](program, input, outputAddress)
- end
- const runProgram(program::Program) = begin
- while !program.halted
- doOperation(program)
- end
- end
- function newProgram(str, input, index=0, output=[], relativeBase=0, stopOnOutput=false)
- Program(parseInput(str), index, input, output, relativeBase, false, false, stopOnOutput)
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement