119 lines
2.1 KiB
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
|
||
|
}
|