2019 Complete!

This commit is contained in:
2020-11-06 15:04:08 -06:00
parent fd5be536a3
commit d6caa5a79d
11 changed files with 2733 additions and 109 deletions

View File

@@ -0,0 +1,118 @@
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
}

View File

@@ -1,12 +1,15 @@
package intcodeprocessor
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"math"
"os"
"strings"
"time"
helpers "git.bullercodeworks.com/brian/adventofcode/helpers"
)
@@ -37,21 +40,23 @@ const (
)
type Program struct {
originalCode []int
code []int
ptr int
relBase int
OriginalCode []int
Code []int
Ptr int
RelBase int
state int
error error
State int
Error error
bail bool
waitingForInput bool
input chan int
waitingForOutput bool
output chan int
Pause bool
Bail bool
WaitingForInput bool
InputChan chan int
WaitingForOutput bool
OutputChan chan int
debug bool
Debug bool
DebugToFile bool
}
func ReadIntCodeFile(fn string) []int {
@@ -70,157 +75,180 @@ func ReadIntCodeFile(fn string) []int {
func NewProgram(prog []int) *Program {
p := new(Program)
p.originalCode = make([]int, len(prog))
p.code = make([]int, len(prog))
copy(p.originalCode, prog)
p.OriginalCode = make([]int, len(prog))
p.Code = make([]int, len(prog))
copy(p.OriginalCode, prog)
p.Reset()
return p
}
func (p *Program) EnableDebug() {
p.debug = true
func (p *Program) SaveState(slot string) error {
f, err := os.OpenFile("saveslot-"+slot+".sav", os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer f.Close()
enc := json.NewEncoder(f)
enc.Encode(p)
return nil
}
func (p *Program) DisableDebug() {
p.debug = false
func (p *Program) LoadState(slot string) error {
hold, err := ioutil.ReadFile("saveslot-" + slot + ".sav")
if err != nil {
return err
}
json.NewDecoder(bytes.NewBuffer(hold)).Decode(&p)
return nil
}
func (p *Program) Pointer() int {
return p.Ptr
}
func (p *Program) DebugLog(l string) {
if p.debug {
if p.Debug {
fmt.Print(l)
}
}
func (p *Program) OutputToFile(l string) {
f, err := os.OpenFile("debug-log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
fmt.Println(err)
return
}
defer f.Close()
_, err = fmt.Fprintln(f, l)
}
func (p *Program) Reset() {
copy(p.code, p.originalCode)
p.ptr = 0
p.state = RET_OK
p.error = nil
p.waitingForInput = false
p.waitingForOutput = false
p.input = make(chan int)
p.output = make(chan int)
p.relBase = 0
}
func (p *Program) GetCode() []int {
return p.code
}
func (p *Program) State() int {
return p.state
}
func (p *Program) Error() error {
return p.error
copy(p.Code, p.OriginalCode)
p.Ptr = 0
p.State = RET_OK
p.Error = nil
p.Pause = false
p.WaitingForInput = false
p.WaitingForOutput = false
p.InputChan = make(chan int)
p.OutputChan = make(chan int)
p.RelBase = 0
}
func (p *Program) ForceQuit() {
p.bail = true
close(p.input)
close(p.output)
p.Bail = true
close(p.InputChan)
close(p.OutputChan)
}
func (p *Program) Run() int {
for {
p.state = p.Step()
if p.state != RET_OK {
return p.state
p.State = p.Step()
if p.State != RET_OK {
return p.State
}
}
}
func (p *Program) Step() int {
if p.bail {
p.error = errors.New("Force Quit")
for p.Pause {
time.Sleep(1)
}
if p.Bail {
p.Error = errors.New("Force Quit")
return RET_ERR
}
if len(p.code) < p.ptr {
p.error = errors.New("Pointer Exception")
if len(p.Code) < p.Ptr {
p.Error = errors.New("Pointer Exception")
return RET_ERR
}
p.DebugLog(p.String() + "\n")
intcode := p.readNext()
p.ptr++
p.Ptr++
switch p.opCode(intcode) {
case OP_ADD:
v1, v2, v3 := p.readNextThree()
p.DebugLog(fmt.Sprintf("ADD %d (%d, %d, %d)\n", intcode, v1, v2, v3))
p.ptr = p.ptr + 3
debug := fmt.Sprintf("ADD %d (%d, %d, %d)\n", intcode, v1, v2, v3)
p.DebugLog(debug)
if p.DebugToFile {
p.OutputToFile(fmt.Sprintf("%d: %s", p.Ptr, debug))
}
p.Ptr = p.Ptr + 3
p.opAdd(intcode, v1, v2, v3)
if p.error != nil {
if p.Error != nil {
return RET_ERR
}
return RET_OK
case OP_MLT:
v1, v2, v3 := p.readNextThree()
p.DebugLog(fmt.Sprintf("MLT %d (%d, %d, %d)\n", intcode, v1, v2, v3))
p.ptr = p.ptr + 3
p.Ptr = p.Ptr + 3
p.opMult(intcode, v1, v2, v3)
if p.error != nil {
if p.Error != nil {
return RET_ERR
}
return RET_OK
case OP_INP:
v1 := p.readNext()
p.DebugLog(fmt.Sprintf("INP %d (%d)\n", intcode, v1))
p.ptr++
p.Ptr++
p.opInp(intcode, v1)
if p.error != nil {
if p.Error != nil {
return RET_ERR
}
return RET_OK
case OP_OUT:
v1 := p.readNext()
p.ptr++
p.Ptr++
p.DebugLog(fmt.Sprintf("OUT %d (%d)\n", intcode, v1))
p.opOut(intcode, v1)
if p.error != nil {
if p.Error != nil {
return RET_ERR
}
return RET_OK
case OP_JIT:
v1, v2 := p.readNextTwo()
p.DebugLog(fmt.Sprintf("JIT %d (%d, %d)\n", intcode, v1, v2))
p.ptr = p.ptr + 2
p.Ptr = p.Ptr + 2
p.opJumpIfTrue(intcode, v1, v2)
if p.error != nil {
if p.Error != nil {
return RET_ERR
}
return RET_OK
case OP_JIF:
v1, v2 := p.readNextTwo()
p.DebugLog(fmt.Sprintf("JIF %d (%d, %d)\n", intcode, v1, v2))
p.ptr = p.ptr + 2
p.Ptr = p.Ptr + 2
p.opJumpIfFalse(intcode, v1, v2)
if p.error != nil {
if p.Error != nil {
return RET_ERR
}
return RET_OK
case OP_ILT:
v1, v2, dest := p.readNextThree()
p.DebugLog(fmt.Sprintf("ILT %d (%d, %d, %d)\n", intcode, v1, v2, dest))
p.ptr = p.ptr + 3
p.Ptr = p.Ptr + 3
p.opIfLessThan(intcode, v1, v2, dest)
if p.error != nil {
if p.Error != nil {
return RET_ERR
}
return RET_OK
case OP_IEQ:
v1, v2, dest := p.readNextThree()
p.DebugLog(fmt.Sprintf("IEQ %d (%d, %d, %d)\n", intcode, v1, v2, dest))
p.ptr = p.ptr + 3
debug := fmt.Sprintf("IEQ %d (%d, %d, %d)\n", intcode, v1, v2, dest)
p.DebugLog(debug)
p.Ptr = p.Ptr + 3
p.opIfEqual(intcode, v1, v2, dest)
if p.error != nil {
if p.Error != nil {
return RET_ERR
}
return RET_OK
case OP_RBS:
v1 := p.readNext()
p.DebugLog(fmt.Sprintf("RBS %d (%d)\n", intcode, v1))
p.ptr = p.ptr + 1
p.Ptr = p.Ptr + 1
p.opModRelBase(intcode, v1)
if p.error != nil {
if p.Error != nil {
return RET_ERR
}
return RET_OK
@@ -229,31 +257,31 @@ func (p *Program) Step() int {
p.DebugLog(fmt.Sprintf("EXT %d\n", intcode))
return RET_DONE
}
p.error = errors.New(fmt.Sprintf("Invalid OpCode (%d)", intcode))
p.Error = errors.New(fmt.Sprintf("Invalid OpCode (%d)", intcode))
p.DebugLog(p.String())
return RET_ERR
}
func (p *Program) GetCurrentOpCode() int {
return p.code[p.ptr]
return p.Code[p.Ptr]
}
func (p *Program) GetProgramValueAt(idx int) int {
p.ensureLength(idx)
return p.code[idx]
return p.Code[idx]
}
func (p *Program) SetProgramValueAt(idx, val int) {
p.ensureLength(idx)
p.code[idx] = val
p.Code[idx] = val
}
func (p *Program) NeedsInput() bool {
return p.waitingForInput
return p.WaitingForInput
}
func (p *Program) NeedsOutput() bool {
return p.waitingForOutput
return p.WaitingForOutput
}
func (p *Program) opCode(intcode int) int {
@@ -266,33 +294,33 @@ func (p *Program) paramMode(intcode, pNum int) int {
}
func (p *Program) ensureLength(idx int) {
for len(p.code) < idx+1 {
p.code = append(p.code, 0)
for len(p.Code) < idx+1 {
p.Code = append(p.Code, 0)
}
}
func (p *Program) readNext() int {
p.ensureLength(p.ptr)
return p.code[p.ptr]
p.ensureLength(p.Ptr)
return p.Code[p.Ptr]
}
func (p *Program) readNextTwo() (int, int) {
p.ensureLength(p.ptr + 1)
return p.code[p.ptr], p.code[p.ptr+1]
p.ensureLength(p.Ptr + 1)
return p.Code[p.Ptr], p.Code[p.Ptr+1]
}
func (p *Program) readNextThree() (int, int, int) {
p.ensureLength(p.ptr + 2)
return p.code[p.ptr], p.code[p.ptr+1], p.code[p.ptr+2]
p.ensureLength(p.Ptr + 2)
return p.Code[p.Ptr], p.Code[p.Ptr+1], p.Code[p.Ptr+2]
}
func (p *Program) get(mode, v int) int {
if mode == MODE_POS {
p.ensureLength(v)
return p.code[v]
return p.Code[v]
} else if mode == MODE_REL {
p.ensureLength(p.relBase + v)
return p.code[p.relBase+v]
p.ensureLength(p.RelBase + v)
return p.Code[p.RelBase+v]
}
return v
}
@@ -300,21 +328,21 @@ func (p *Program) get(mode, v int) int {
func (p *Program) set(mode, idx, v int) {
if mode == MODE_POS {
p.ensureLength(idx)
p.code[idx] = v
p.Code[idx] = v
} else if mode == MODE_REL {
p.ensureLength(p.relBase + idx)
p.code[p.relBase+idx] = v
p.ensureLength(p.RelBase + idx)
p.Code[p.RelBase+idx] = v
}
}
func (p *Program) Input(v int) {
p.input <- v
//p.waitingForInput = false
p.InputChan <- v
//p.WaitingForInput = false
}
func (p *Program) Output() int {
v := <-p.output
p.waitingForOutput = false
v := <-p.OutputChan
p.WaitingForOutput = false
return v
}
@@ -330,29 +358,29 @@ func (p *Program) opMult(intcode, a1, a2, dest int) {
func (p *Program) opInp(intcode, dest int) {
destmd := p.paramMode(intcode, 0)
p.waitingForInput = true
p.set(destmd, dest, <-p.input)
p.waitingForInput = false
p.WaitingForInput = true
p.set(destmd, dest, <-p.InputChan)
p.WaitingForInput = false
}
func (p *Program) opOut(intcode, val int) {
valmd := p.paramMode(intcode, 0)
ret := p.get(valmd, val)
p.waitingForOutput = true
p.output <- ret
p.WaitingForOutput = true
p.OutputChan <- ret
}
func (p *Program) opJumpIfTrue(intcode, v1, v2 int) {
v1md, v2md := p.paramMode(intcode, 0), p.paramMode(intcode, 1)
if p.get(v1md, v1) != 0 {
p.ptr = p.get(v2md, v2)
p.Ptr = p.get(v2md, v2)
}
}
func (p *Program) opJumpIfFalse(intcode, v1, v2 int) {
v1md, v2md := p.paramMode(intcode, 0), p.paramMode(intcode, 1)
if p.get(v1md, v1) == 0 {
p.ptr = p.get(v2md, v2)
p.Ptr = p.get(v2md, v2)
}
}
@@ -376,17 +404,17 @@ func (p *Program) opIfEqual(intcode, v1, v2, dest int) {
func (p *Program) opModRelBase(intcode, v1 int) {
v1md := p.paramMode(intcode, 0)
p.relBase = p.relBase + p.get(v1md, v1)
p.RelBase = p.RelBase + p.get(v1md, v1)
}
func (p Program) String() string {
var ret string
ret = ret + fmt.Sprintf("(PTR: %d, RBS: %d)\n", p.ptr, p.relBase)
for k := range p.code {
if k == p.ptr {
ret = fmt.Sprintf("%s [%d]", ret, p.code[k])
ret = ret + fmt.Sprintf("(PTR: %d, RBS: %d)\n", p.Ptr, p.RelBase)
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])
ret = fmt.Sprintf("%s %d", ret, p.Code[k])
}
}
return ret