AoC/2019/AoC.playground/Sources/IntCode.swift

119 lines
2.5 KiB
Swift
Raw Normal View History

2022-11-23 16:46:51 +01:00
func pow(base: Int = 10, _ n: Int) -> Int {
precondition( n >= 0 )
switch n {
case 0: return 1
case 1: return base
case _ where n.isMultiple(of: 2):
return pow(base: base * base, n / 2)
default:
return base * pow(base: base * base, n / 2)
}
}
public protocol IO: class {
func input() -> Int
func output(_ value: Int)
}
public class IntCode {
var memory: [Int]
var pc = 0
var base = 0
var io: IO
public init(program: [Int], io: IO) {
self.memory = program
self.io = io
}
func address(_ index: Int) -> Int {
let mode = (memory[pc] / pow(2 + index - 1)) % 10
switch mode {
case 0: return memory[pc + index]
case 1: return pc + index
case 2: return memory[pc + index] + base
default: preconditionFailure("Unknown mode \(mode)")
}
}
func get(_ index: Int) -> Int {
let addr = address(index)
return addr < memory.count ? memory[addr] : 0
}
func put(_ index: Int, value: Int) {
let addr = address(index)
let toAdd = addr - memory.count + 1
if toAdd > 0 {
memory.append(contentsOf: Array(repeating: 0, count: toAdd))
}
memory[addr] = value
}
public func run() {
loop: while(true) {
let opcode = memory[pc] % 100
switch opcode {
case 1:
put(3, value: get(1) + get(2))
pc += 4
case 2:
put(3, value: get(1) * get(2))
pc += 4
case 3:
put(1, value: io.input())
pc += 2
case 4:
io.output(get(1))
pc += 2
case 5:
if get(1) != 0 {
pc = get(2)
} else {
pc += 3
}
case 6:
if get(1) == 0 {
pc = get(2)
} else {
pc += 3
}
case 7:
put(3, value: get(1) < get(2) ? 1 : 0)
pc += 4
case 8:
put(3, value: get(1) == get(2) ? 1 : 0)
pc += 4
case 9:
base += get(1)
pc += 2
case 99:
break loop
default:
preconditionFailure("Unknown opcode \(opcode)")
}
}
}
}