adventofcode/2019/intcode-processor/opt_proc.go

119 lines
2.1 KiB
Go

package intcodeprocessor
import (
"fmt"
"math"
"strconv"
)
type OptProc struct {
OriginalCode []int
Code []int
Ptr int
RelBase int
State int
Error error
Pause bool
Bail bool
WaitingForInput bool
WaitingForOutput bool
Debug bool
DebugToFile bool
}
func NewOptProc(prog []int) *OptProc {
p := new(OptProc)
p.State = RET_OK
p.OriginalCode = make([]int, len(prog))
max := math.MaxInt16
if 2*len(prog) > max {
max = 2 * len(prog)
}
p.Code = make([]int, max)
copy(p.OriginalCode, prog)
return p
}
func (p *OptProc) Run(in <-chan int, out chan<- int) int {
p.Ptr = 0
p.RelBase = 0
copy(p.Code, p.OriginalCode)
for p.State == RET_OK {
ins := fmt.Sprintf("%05d", p.Code[p.Ptr])
opcode, _ := strconv.Atoi(ins[3:])
arg := func(i int) int {
switch ins[3-i] {
case '1': // Immediate mode
return p.Ptr + i
case '2': // Relative mode
return p.RelBase + p.Code[p.Ptr+i]
default: // 1, position mode
return p.Code[p.Ptr+i]
}
}
switch opcode {
case OP_ADD:
p.Code[arg(3)] = p.Code[arg(1)] + p.Code[arg(2)]
p.Ptr = p.Ptr + 4
case OP_MLT:
p.Code[arg(3)] = p.Code[arg(1)] * p.Code[arg(2)]
p.Ptr += 4
case OP_INP:
p.WaitingForInput = true
v := <-in
p.WaitingForInput = false
p.Code[arg(1)] = v
p.Ptr += 2
case OP_OUT:
p.WaitingForOutput = true
out <- p.Code[arg(1)]
p.WaitingForOutput = false
p.Ptr += 2
case OP_JIT:
if p.Code[arg(1)] != 0 {
p.Ptr = p.Code[arg(2)]
} else {
p.Ptr += 3
}
case OP_JIF:
if p.Code[arg(1)] == 0 {
p.Ptr = p.Code[arg(2)]
} else {
p.Ptr += 3
}
case OP_ILT:
if p.Code[arg(1)] < p.Code[arg(2)] {
p.Code[arg(3)] = 1
} else {
p.Code[arg(3)] = 0
}
p.Ptr += 4
case OP_IEQ:
if p.Code[arg(1)] == p.Code[arg(2)] {
p.Code[arg(3)] = 1
} else {
p.Code[arg(3)] = 0
}
p.Ptr += 4
case OP_RBS:
p.RelBase += p.Code[arg(1)]
p.Ptr += 2
case OP_EXT:
p.State = RET_DONE
default:
p.State = RET_ERR
}
}
return p.State
}
func (p *OptProc) IsStopped() bool {
return p.State != RET_OK
}