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 }