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 }