118 lines
2.5 KiB
Swift
118 lines
2.5 KiB
Swift
|
|
|
|
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)")
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|