1
0
Fork 0
mirror of https://github.com/Luzifer/aoc2019.git synced 2024-10-18 11:14:19 +00:00
aoc2019/intcode.go
Knut Ahlers 90216aba66
Add solution for Day 7
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2019-12-07 22:57:10 +01:00

174 lines
3.4 KiB
Go

package aoc2019
import (
"reflect"
"strconv"
"strings"
"github.com/pkg/errors"
)
type opCodeFlag int
const (
opCodeFlagPosition opCodeFlag = iota
opCodeFlagImmediate
)
type opCodeType int
const (
opCodeTypeAddition opCodeType = 1 // Day 02
opCodeTypeMultiplication opCodeType = 2 // Day 02
opCodeTypeInput opCodeType = 3 // Day 05 P1
opCodeTypeOutput opCodeType = 4 // Day 05 P1
opCodeTypeJumpIfTrue opCodeType = 5 // Day 05 P2
opCodeTypeJumpIfFalse opCodeType = 6 // Day 05 P2
opCodeTypeLessThan opCodeType = 7 // Day 05 P2
opCodeTypeEquals opCodeType = 8 // Day 05 P2
opCodeTypeExit opCodeType = 99 // Day 02
)
type opCode struct {
Type opCodeType
flags []opCodeFlag
}
func (o opCode) GetFlag(param int) opCodeFlag {
if param-1 >= len(o.flags) {
return opCodeFlagPosition
}
return o.flags[param-1]
}
func (o opCode) eq(in opCode) bool {
return o.Type == in.Type && reflect.DeepEqual(o.flags, in.flags)
}
func parseOpCode(in int) opCode {
out := opCode{}
out.Type = opCodeType(in % 100)
var paramFactor = 100
for {
if in < paramFactor {
break
}
out.flags = append(out.flags, opCodeFlag((in % (paramFactor * 10) / paramFactor)))
paramFactor *= 10
}
return out
}
func cloneIntcode(in []int) []int {
out := make([]int, len(in))
for i, v := range in {
out[i] = v
}
return out
}
func parseIntcode(code string) ([]int, error) {
parts := strings.Split(code, ",")
var out []int
for _, n := range parts {
v, err := strconv.Atoi(n)
if err != nil {
return nil, err
}
out = append(out, v)
}
return out, nil
}
func executeIntcode(code []int, in, out chan int) ([]int, error) {
var pos int
if out != nil {
defer close(out)
}
getParamValue := func(param int, op opCode) int {
switch op.GetFlag(param) {
case opCodeFlagImmediate:
return code[pos+param]
case opCodeFlagPosition:
return code[code[pos+param]]
default:
panic(errors.Errorf("Unexpected opCodeFlag %d", op.GetFlag(param)))
}
}
for {
if pos >= len(code) {
return nil, errors.Errorf("Code position out of bounds: %d (len=%d)", pos, len(code))
}
// Position is expected to be an OpCode
op := parseOpCode(code[pos])
switch op.Type {
case opCodeTypeAddition: // p1 + p2 => p3
code[code[pos+3]] = getParamValue(1, op) + getParamValue(2, op)
pos += 4
case opCodeTypeMultiplication: // p1 * p2 => p3
code[code[pos+3]] = getParamValue(1, op) * getParamValue(2, op)
pos += 4
case opCodeTypeInput: // in => p1
code[code[pos+1]] = <-in
pos += 2
case opCodeTypeOutput: // p1 => out
out <- getParamValue(1, op)
pos += 2
case opCodeTypeJumpIfTrue: // p1 != 0 => jmp
if getParamValue(1, op) != 0 {
pos = getParamValue(2, op)
continue
}
pos += 3
case opCodeTypeJumpIfFalse: // p1 == 0 => jmp
if getParamValue(1, op) == 0 {
pos = getParamValue(2, op)
continue
}
pos += 3
case opCodeTypeLessThan: // p1 < p2 => p3
var res int
if getParamValue(1, op) < getParamValue(2, op) {
res = 1
}
code[code[pos+3]] = res
pos += 4
case opCodeTypeEquals: // p1 == p2 => p3
var res int
if getParamValue(1, op) == getParamValue(2, op) {
res = 1
}
code[code[pos+3]] = res
pos += 4
case opCodeTypeExit: // exit
return code, nil
default:
return nil, errors.Errorf("Encountered invalid operation %d (parsed %#v)", code[pos], op)
}
}
}