adventofcode/2019/intcode-processor/processor.go

122 lines
1.8 KiB
Go

package intcodeprocessor
import (
"errors"
"fmt"
)
const (
OP_ADD = 1
OP_MLT = 2
OP_EXT = 99
)
const (
RET_ERR = iota - 1
RET_OK
RET_DONE
)
type Program struct {
code []int
ptr int
state int
error error
}
func NewProgram(prog []int) *Program {
p := new(Program)
p.code = make([]int, len(prog))
copy(p.code, prog)
return p
}
func (p *Program) State() int {
return p.state
}
func (p *Program) Error() error {
return p.error
}
func (p *Program) Run() int {
for {
p.state = p.Step()
switch p.state {
case RET_ERR:
return RET_ERR
case RET_DONE:
return RET_DONE
}
}
}
func (p *Program) Step() int {
if len(p.code) < p.ptr {
p.error = errors.New("Pointer Exception")
return RET_ERR
}
switch p.readNext() {
case OP_ADD:
p.add(p.readNextThree())
if p.error != nil {
return RET_ERR
}
return RET_OK
case OP_MLT:
p.mult(p.readNextThree())
if p.error != nil {
return RET_ERR
}
return RET_OK
case OP_EXT:
return RET_DONE
}
return RET_ERR
}
func (p *Program) GetProgramValueAt(idx int) int {
return p.code[idx]
}
func (p *Program) SetProgramValueAt(idx, val int) {
p.code[idx] = val
}
func (p *Program) readNext() int {
if len(p.code) <= p.ptr {
p.error = errors.New("Pointer Exception")
}
p.ptr++
return p.code[p.ptr-1]
}
func (p *Program) readNextTwo() (int, int) {
return p.readNext(), p.readNext()
}
func (p *Program) readNextThree() (int, int, int) {
return p.readNext(), p.readNext(), p.readNext()
}
func (p *Program) add(a1, a2, dest int) {
p.code[dest] = p.code[a1] + p.code[a2]
}
func (p *Program) mult(a1, a2, dest int) {
p.code[dest] = p.code[a1] * p.code[a2]
}
func (p Program) String() string {
var ret string
for k := range p.code {
if k == p.ptr {
ret = fmt.Sprintf("%s [%d]", ret, p.code[k])
} else {
ret = fmt.Sprintf("%s %d", ret, p.code[k])
}
}
return ret
}