1
0
Fork 0
mirror of https://github.com/Luzifer/aoc2019.git synced 2024-10-18 11:14:19 +00:00

Add solution for Day 9

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2019-12-09 18:48:40 +01:00
parent b516f08460
commit d11d14dfb9
Signed by: luzifer
GPG key ID: DC2729FDD34BE99E
10 changed files with 262 additions and 76 deletions

View file

@ -7,13 +7,13 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
func parseDay02Intcode(code string) ([]int, error) { return parseIntcode(code) } func parseDay02Intcode(code string) ([]int64, error) { return parseIntcode(code) }
func executeDay02Intcode(code []int) ([]int, error) { func executeDay02Intcode(code []int64) ([]int64, error) {
return executeIntcode(code, nil, nil) // Day02 intcode may not contain I/O return executeIntcode(code, nil, nil) // Day02 intcode may not contain I/O
} }
func solveDay2Part1(inFile string) (int, error) { func solveDay2Part1(inFile string) (int64, error) {
raw, err := ioutil.ReadFile(inFile) raw, err := ioutil.ReadFile(inFile)
if err != nil { if err != nil {
return 0, errors.Wrap(err, "Unable to read input") return 0, errors.Wrap(err, "Unable to read input")
@ -37,16 +37,16 @@ func solveDay2Part1(inFile string) (int, error) {
return code[0], nil return code[0], nil
} }
func solveDay2Part2(inFile string) (int, error) { func solveDay2Part2(inFile string) (int64, error) {
raw, err := ioutil.ReadFile(inFile) raw, err := ioutil.ReadFile(inFile)
if err != nil { if err != nil {
return 0, errors.Wrap(err, "Unable to read input") return 0, errors.Wrap(err, "Unable to read input")
} }
const expectedResult int = 19690720 const expectedResult int64 = 19690720
for noun := 0; noun < 100; noun++ { for noun := int64(0); noun < 100; noun++ {
for verb := 0; verb < 100; verb++ { for verb := int64(0); verb < 100; verb++ {
// Re-initialize "memory" // Re-initialize "memory"
code, err := parseDay02Intcode(strings.TrimSpace(string(raw))) code, err := parseDay02Intcode(strings.TrimSpace(string(raw)))

View file

@ -6,7 +6,7 @@ import (
) )
func TestExecuteDay02Intcode(t *testing.T) { func TestExecuteDay02Intcode(t *testing.T) {
for codeStr, expResult := range map[string][]int{ for codeStr, expResult := range map[string][]int64{
"1,0,0,0,99": {2, 0, 0, 0, 99}, "1,0,0,0,99": {2, 0, 0, 0, 99},
"2,3,0,3,99": {2, 3, 0, 6, 99}, "2,3,0,3,99": {2, 3, 0, 6, 99},
"2,4,4,5,99,0": {2, 4, 4, 5, 99, 9801}, "2,4,4,5,99,0": {2, 4, 4, 5, 99, 9801},

View file

@ -7,7 +7,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
func solveDay5FromFile(inFile string, diagProgram int) (int, error) { func solveDay5FromFile(inFile string, diagProgram int64) (int64, error) {
raw, err := ioutil.ReadFile(inFile) raw, err := ioutil.ReadFile(inFile)
if err != nil { if err != nil {
return 0, errors.Wrap(err, "Unable to read input") return 0, errors.Wrap(err, "Unable to read input")
@ -19,9 +19,9 @@ func solveDay5FromFile(inFile string, diagProgram int) (int, error) {
} }
var ( var (
in = make(chan int, 1) in = make(chan int64, 1)
out = make(chan int, len(code)) // There cannot be more outputs than number of code parts out = make(chan int64, len(code)) // There cannot be more outputs than number of code parts
outputs []int outputs []int64
) )
/* /*
@ -52,7 +52,7 @@ func solveDay5FromFile(inFile string, diagProgram int) (int, error) {
return outputs[len(outputs)-1], nil return outputs[len(outputs)-1], nil
} }
func solveDay5Part1(inFile string) (int, error) { func solveDay5Part1(inFile string) (int64, error) {
/* /*
* The TEST diagnostic program will start by requesting from the user * The TEST diagnostic program will start by requesting from the user
* the ID of the system to test by running an input instruction - provide * the ID of the system to test by running an input instruction - provide
@ -61,7 +61,7 @@ func solveDay5Part1(inFile string) (int, error) {
return solveDay5FromFile(inFile, 1) return solveDay5FromFile(inFile, 1)
} }
func solveDay5Part2(inFile string) (int, error) { func solveDay5Part2(inFile string) (int64, error) {
/* /*
* This time, when the TEST diagnostic program runs its input * This time, when the TEST diagnostic program runs its input
* instruction to get the ID of the system to test, provide it 5, * instruction to get the ID of the system to test, provide it 5,

View file

@ -7,17 +7,17 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
func day07TestMaxOutputFromChain(code []int, chainStart, chainEnd int, looped bool) int { func day07TestMaxOutputFromChain(code []int64, chainStart, chainEnd int, looped bool) int64 {
var ( var (
chainLen = chainEnd - chainStart + 1 chainLen = chainEnd - chainStart + 1
permuts [][]int permuts [][]int64
permute func(a []int, k int) permute func(a []int64, k int)
rootSeq = make([]int, chainLen) rootSeq = make([]int64, chainLen)
) )
permute = func(a []int, k int) { permute = func(a []int64, k int) {
if k == len(a) { if k == len(a) {
permuts = append(permuts, append([]int{}, a...)) permuts = append(permuts, append([]int64{}, a...))
} else { } else {
for i := k; i < len(rootSeq); i++ { for i := k; i < len(rootSeq); i++ {
a[k], a[i] = a[i], a[k] a[k], a[i] = a[i], a[k]
@ -28,20 +28,20 @@ func day07TestMaxOutputFromChain(code []int, chainStart, chainEnd int, looped bo
} }
for i := range rootSeq { for i := range rootSeq {
rootSeq[i] = chainStart + i rootSeq[i] = int64(chainStart + i)
} }
permute(rootSeq, 0) permute(rootSeq, 0)
var maxOutput int var maxOutput int64
for _, seq := range permuts { for _, seq := range permuts {
var ( var (
commInChans = make([]chan int, chainLen) commInChans = make([]chan int64, chainLen)
commOut = make(chan int, 2) commOut = make(chan int64, 2)
) )
// Create channels // Create channels
for i := range commInChans { for i := range commInChans {
commInChans[i] = make(chan int, 2) commInChans[i] = make(chan int64, 2)
} }
// Build execution chain // Build execution chain
@ -56,7 +56,7 @@ func day07TestMaxOutputFromChain(code []int, chainStart, chainEnd int, looped bo
} }
commInChans[0] <- 0 // Input signal commInChans[0] <- 0 // Input signal
var lastOutput int var lastOutput int64
for r := range commOut { for r := range commOut {
lastOutput = r lastOutput = r
if looped { if looped {
@ -73,7 +73,7 @@ func day07TestMaxOutputFromChain(code []int, chainStart, chainEnd int, looped bo
return maxOutput return maxOutput
} }
func solveDay7Part1(inFile string) (int, error) { func solveDay7Part1(inFile string) (int64, error) {
raw, err := ioutil.ReadFile(inFile) raw, err := ioutil.ReadFile(inFile)
if err != nil { if err != nil {
return 0, errors.Wrap(err, "Unable to read input file") return 0, errors.Wrap(err, "Unable to read input file")
@ -87,7 +87,7 @@ func solveDay7Part1(inFile string) (int, error) {
return day07TestMaxOutputFromChain(code, 0, 4, false), nil return day07TestMaxOutputFromChain(code, 0, 4, false), nil
} }
func solveDay7Part2(inFile string) (int, error) { func solveDay7Part2(inFile string) (int64, error) {
raw, err := ioutil.ReadFile(inFile) raw, err := ioutil.ReadFile(inFile)
if err != nil { if err != nil {
return 0, errors.Wrap(err, "Unable to read input file") return 0, errors.Wrap(err, "Unable to read input file")

View file

@ -10,12 +10,12 @@ func TestChainedInput(t *testing.T) {
// Create channels // Create channels
var ( var (
aIn = make(chan int, 2) aIn = make(chan int64, 2)
bIn = make(chan int, 2) bIn = make(chan int64, 2)
cIn = make(chan int, 2) cIn = make(chan int64, 2)
dIn = make(chan int, 2) dIn = make(chan int64, 2)
eIn = make(chan int, 2) eIn = make(chan int64, 2)
eOut = make(chan int, 2) eOut = make(chan int64, 2)
) )
// Build execution chain // Build execution chain
@ -40,7 +40,7 @@ func TestChainedInput(t *testing.T) {
} }
func TestMaxOutputFromChain(t *testing.T) { func TestMaxOutputFromChain(t *testing.T) {
for codeStr, expValue := range map[string]int{ for codeStr, expValue := range map[string]int64{
"3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0": 43210, "3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0": 43210,
"3,23,3,24,1002,24,10,24,1002,23,-1,23,101,5,23,23,1,24,23,23,4,23,99,0,0": 54321, "3,23,3,24,1002,24,10,24,1002,23,-1,23,101,5,23,23,1,24,23,23,4,23,99,0,0": 54321,
"3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33,1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0": 65210, "3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33,1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0": 65210,
@ -57,7 +57,7 @@ func TestMaxOutputFromChain(t *testing.T) {
} }
func TestMaxOutputFromLoopedChain(t *testing.T) { func TestMaxOutputFromLoopedChain(t *testing.T) {
for codeStr, expValue := range map[string]int{ for codeStr, expValue := range map[string]int64{
"3,26,1001,26,-4,26,3,27,1002,27,2,27,1,27,26,27,4,27,1001,28,-1,28,1005,28,6,99,0,0,5": 139629729, "3,26,1001,26,-4,26,3,27,1002,27,2,27,1,27,26,27,4,27,1001,28,-1,28,1005,28,6,99,0,0,5": 139629729,
"3,52,1001,52,-5,52,3,53,1,52,56,54,1007,54,5,55,1005,55,26,1001,54,-5,54,1105,1,12,1,53,54,53,1008,54,0,55,1001,55,1,55,2,53,55,53,4,53,1001,56,-1,56,1005,56,6,99,0,0,0,0,10": 18216, "3,52,1001,52,-5,52,3,53,1,52,56,54,1007,54,5,55,1005,55,26,1001,54,-5,54,1105,1,12,1,53,54,53,1008,54,0,55,1001,55,1,55,2,53,55,53,4,53,1001,56,-1,56,1005,56,6,99,0,0,0,0,10": 18216,
} { } {

75
day09.go Normal file
View file

@ -0,0 +1,75 @@
package aoc2019
import (
"io/ioutil"
"strings"
"sync"
"github.com/pkg/errors"
)
func solveDay9Part1(inFile string) (int64, error) {
raw, err := ioutil.ReadFile(inFile)
if err != nil {
return 0, errors.Wrap(err, "Unable to read input file")
}
code, err := parseIntcode(strings.TrimSpace(string(raw)))
if err != nil {
return 0, errors.Wrap(err, "Unable to parse intcode program")
}
var (
inChan = make(chan int64, 1)
outChan = make(chan int64, 1)
output []int64
wg sync.WaitGroup
)
inChan <- 1
wg.Add(1)
go func() {
for v := range outChan {
output = append(output, v)
}
wg.Done()
}()
if _, err := executeIntcode(code, inChan, outChan); err != nil {
return 0, errors.Wrap(err, "Unable to execute intcode")
}
wg.Wait()
if len(output) != 1 {
return 0, errors.Errorf("Got malfunction information: %+v", output)
}
return output[0], nil
}
func solveDay9Part2(inFile string) (int64, error) {
raw, err := ioutil.ReadFile(inFile)
if err != nil {
return 0, errors.Wrap(err, "Unable to read input file")
}
code, err := parseIntcode(strings.TrimSpace(string(raw)))
if err != nil {
return 0, errors.Wrap(err, "Unable to parse intcode program")
}
var (
inChan = make(chan int64, 1)
outChan = make(chan int64, 1)
)
inChan <- 2
if _, err := executeIntcode(code, inChan, outChan); err != nil {
return 0, errors.Wrap(err, "Unable to execute intcode")
}
return <-outChan, nil
}

1
day09_input.txt Normal file
View file

@ -0,0 +1 @@
1102,34463338,34463338,63,1007,63,34463338,63,1005,63,53,1102,1,3,1000,109,988,209,12,9,1000,209,6,209,3,203,0,1008,1000,1,63,1005,63,65,1008,1000,2,63,1005,63,904,1008,1000,0,63,1005,63,58,4,25,104,0,99,4,0,104,0,99,4,17,104,0,99,0,0,1101,0,0,1020,1101,34,0,1004,1101,0,26,1008,1102,1,37,1011,1101,39,0,1018,1102,587,1,1022,1101,1,0,1021,1102,22,1,1012,1101,0,33,1014,1101,24,0,1016,1101,0,752,1029,1101,36,0,1002,1101,35,0,1006,1101,32,0,1009,1102,38,1,1003,1102,584,1,1023,1101,0,20,1001,1102,892,1,1025,1102,29,1,1000,1101,411,0,1026,1102,1,901,1024,1101,0,761,1028,1101,23,0,1017,1102,30,1,1013,1101,0,27,1015,1102,28,1,1005,1101,408,0,1027,1101,25,0,1007,1102,31,1,1019,1101,0,21,1010,109,5,1207,-2,39,63,1005,63,199,4,187,1105,1,203,1001,64,1,64,1002,64,2,64,109,12,21102,40,1,-1,1008,1016,40,63,1005,63,229,4,209,1001,64,1,64,1106,0,229,1002,64,2,64,109,-5,1207,-5,24,63,1005,63,249,1001,64,1,64,1106,0,251,4,235,1002,64,2,64,109,-14,2102,1,6,63,1008,63,32,63,1005,63,271,1106,0,277,4,257,1001,64,1,64,1002,64,2,64,109,2,1202,1,1,63,1008,63,20,63,1005,63,303,4,283,1001,64,1,64,1106,0,303,1002,64,2,64,109,7,2108,34,2,63,1005,63,319,1106,0,325,4,309,1001,64,1,64,1002,64,2,64,109,6,2101,0,-6,63,1008,63,24,63,1005,63,349,1001,64,1,64,1105,1,351,4,331,1002,64,2,64,109,4,21107,41,42,0,1005,1017,369,4,357,1105,1,373,1001,64,1,64,1002,64,2,64,109,5,21101,42,0,-5,1008,1017,41,63,1005,63,397,1001,64,1,64,1106,0,399,4,379,1002,64,2,64,109,9,2106,0,-4,1106,0,417,4,405,1001,64,1,64,1002,64,2,64,109,-20,21108,43,43,0,1005,1011,435,4,423,1105,1,439,1001,64,1,64,1002,64,2,64,109,-15,2102,1,8,63,1008,63,34,63,1005,63,465,4,445,1001,64,1,64,1105,1,465,1002,64,2,64,109,3,1201,6,0,63,1008,63,28,63,1005,63,491,4,471,1001,64,1,64,1106,0,491,1002,64,2,64,109,18,21108,44,46,0,1005,1017,511,1001,64,1,64,1106,0,513,4,497,1002,64,2,64,109,12,1205,-8,527,4,519,1105,1,531,1001,64,1,64,1002,64,2,64,109,-17,1208,-3,32,63,1005,63,553,4,537,1001,64,1,64,1105,1,553,1002,64,2,64,109,-13,1208,10,31,63,1005,63,573,1001,64,1,64,1105,1,575,4,559,1002,64,2,64,109,17,2105,1,7,1105,1,593,4,581,1001,64,1,64,1002,64,2,64,109,-8,2107,19,-7,63,1005,63,615,4,599,1001,64,1,64,1105,1,615,1002,64,2,64,109,4,1206,8,629,4,621,1106,0,633,1001,64,1,64,1002,64,2,64,109,-2,2101,0,-6,63,1008,63,34,63,1005,63,655,4,639,1105,1,659,1001,64,1,64,1002,64,2,64,109,10,1205,0,671,1105,1,677,4,665,1001,64,1,64,1002,64,2,64,109,-21,2107,26,8,63,1005,63,693,1106,0,699,4,683,1001,64,1,64,1002,64,2,64,109,19,1201,-9,0,63,1008,63,30,63,1005,63,719,1105,1,725,4,705,1001,64,1,64,1002,64,2,64,109,9,1206,-6,741,1001,64,1,64,1106,0,743,4,731,1002,64,2,64,109,-5,2106,0,6,4,749,1001,64,1,64,1105,1,761,1002,64,2,64,109,-14,1202,-1,1,63,1008,63,27,63,1005,63,781,1105,1,787,4,767,1001,64,1,64,1002,64,2,64,109,1,21107,45,44,5,1005,1014,807,1001,64,1,64,1105,1,809,4,793,1002,64,2,64,109,8,21101,46,0,0,1008,1017,46,63,1005,63,835,4,815,1001,64,1,64,1106,0,835,1002,64,2,64,109,-26,2108,20,10,63,1005,63,857,4,841,1001,64,1,64,1106,0,857,1002,64,2,64,109,24,21102,47,1,-5,1008,1010,46,63,1005,63,881,1001,64,1,64,1106,0,883,4,863,1002,64,2,64,109,6,2105,1,3,4,889,1001,64,1,64,1105,1,901,4,64,99,21102,27,1,1,21101,915,0,0,1105,1,922,21201,1,29830,1,204,1,99,109,3,1207,-2,3,63,1005,63,964,21201,-2,-1,1,21101,0,942,0,1105,1,922,21202,1,1,-1,21201,-2,-3,1,21102,1,957,0,1105,1,922,22201,1,-1,-2,1105,1,968,21201,-2,0,-2,109,-3,2106,0,0

21
day09_test.go Normal file
View file

@ -0,0 +1,21 @@
package aoc2019
import "testing"
func TestCalculateDay9_Part1(t *testing.T) {
codeP0, err := solveDay9Part1("day09_input.txt")
if err != nil {
t.Fatalf("Day 9 solver failed: %s", err)
}
t.Logf("Solution Day 9 Part 1: %d", codeP0)
}
func TestCalculateDay9_Part2(t *testing.T) {
result, err := solveDay9Part2("day09_input.txt")
if err != nil {
t.Fatalf("Day 9 solver failed: %s", err)
}
t.Logf("Solution Day 9 Part 2: %d", result)
}

View file

@ -8,14 +8,15 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
type opCodeFlag int type opCodeFlag int64
const ( const (
opCodeFlagPosition opCodeFlag = iota opCodeFlagPosition opCodeFlag = iota
opCodeFlagImmediate opCodeFlagImmediate
opCodeFlagRelative
) )
type opCodeType int type opCodeType int64
const ( const (
opCodeTypeAddition opCodeType = 1 // Day 02 opCodeTypeAddition opCodeType = 1 // Day 02
@ -26,6 +27,7 @@ const (
opCodeTypeJumpIfFalse opCodeType = 6 // Day 05 P2 opCodeTypeJumpIfFalse opCodeType = 6 // Day 05 P2
opCodeTypeLessThan opCodeType = 7 // Day 05 P2 opCodeTypeLessThan opCodeType = 7 // Day 05 P2
opCodeTypeEquals opCodeType = 8 // Day 05 P2 opCodeTypeEquals opCodeType = 8 // Day 05 P2
opCodeTypeAdjRelBase opCodeType = 9 // Day 09
opCodeTypeExit opCodeType = 99 // Day 02 opCodeTypeExit opCodeType = 99 // Day 02
) )
@ -34,8 +36,8 @@ type opCode struct {
flags []opCodeFlag flags []opCodeFlag
} }
func (o opCode) GetFlag(param int) opCodeFlag { func (o opCode) GetFlag(param int64) opCodeFlag {
if param-1 >= len(o.flags) { if param-1 >= int64(len(o.flags)) {
return opCodeFlagPosition return opCodeFlagPosition
} }
return o.flags[param-1] return o.flags[param-1]
@ -45,12 +47,12 @@ func (o opCode) eq(in opCode) bool {
return o.Type == in.Type && reflect.DeepEqual(o.flags, in.flags) return o.Type == in.Type && reflect.DeepEqual(o.flags, in.flags)
} }
func parseOpCode(in int) opCode { func parseOpCode(in int64) opCode {
out := opCode{} out := opCode{}
out.Type = opCodeType(in % 100) out.Type = opCodeType(in % 100)
var paramFactor = 100 var paramFactor int64 = 100
for { for {
if in < paramFactor { if in < paramFactor {
break break
@ -63,20 +65,20 @@ func parseOpCode(in int) opCode {
return out return out
} }
func cloneIntcode(in []int) []int { func cloneIntcode(in []int64) []int64 {
out := make([]int, len(in)) out := make([]int64, len(in))
for i, v := range in { for i, v := range in {
out[i] = v out[i] = v
} }
return out return out
} }
func parseIntcode(code string) ([]int, error) { func parseIntcode(code string) ([]int64, error) {
parts := strings.Split(code, ",") parts := strings.Split(code, ",")
var out []int var out []int64
for _, n := range parts { for _, n := range parts {
v, err := strconv.Atoi(n) v, err := strconv.ParseInt(n, 10, 64)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -86,30 +88,69 @@ func parseIntcode(code string) ([]int, error) {
return out, nil return out, nil
} }
func executeIntcode(code []int, in, out chan int) ([]int, error) { func executeIntcode(code []int64, in, out chan int64) ([]int64, error) {
var pos int var (
pos int64
relativeBase int64
)
if out != nil { if out != nil {
defer close(out) defer close(out)
} }
getParamValue := func(param int, op opCode) int { transformPos := func(param int64, op opCode, write bool) int64 {
var addr int64
switch op.GetFlag(param) { switch op.GetFlag(param) {
case opCodeFlagImmediate: case opCodeFlagImmediate:
return code[pos+param] if write {
addr = code[pos+param]
} else {
addr = pos + param
}
case opCodeFlagPosition: case opCodeFlagPosition:
return code[code[pos+param]] addr = code[pos+param]
case opCodeFlagRelative:
addr = code[pos+param] + int64(relativeBase)
default: default:
panic(errors.Errorf("Unexpected opCodeFlag %d", op.GetFlag(param))) panic(errors.Errorf("Unexpected opCodeFlag %d", op.GetFlag(param)))
} }
return addr
}
getParamValue := func(param int64, op opCode) int64 {
var addr = transformPos(param, op, false)
if addr >= int64(len(code)) {
return 0
}
return code[addr]
}
setParamValue := func(param, value int64, op opCode) {
var addr = transformPos(param, op, false)
if addr >= int64(len(code)) {
// Write outside memory, increase memory
var tmp = make([]int64, addr+1)
for i, v := range code {
tmp[i] = v
}
code = tmp
}
code[addr] = value
} }
for { for {
if pos >= len(code) { if pos >= int64(len(code)) {
return nil, errors.Errorf("Code position out of bounds: %d (len=%d)", pos, len(code)) return nil, errors.Errorf("Code position out of bounds: %d (len=%d)", pos, len(code))
} }
@ -118,15 +159,15 @@ func executeIntcode(code []int, in, out chan int) ([]int, error) {
switch op.Type { switch op.Type {
case opCodeTypeAddition: // p1 + p2 => p3 case opCodeTypeAddition: // p1 + p2 => p3
code[code[pos+3]] = getParamValue(1, op) + getParamValue(2, op) setParamValue(3, getParamValue(1, op)+getParamValue(2, op), op)
pos += 4 pos += 4
case opCodeTypeMultiplication: // p1 * p2 => p3 case opCodeTypeMultiplication: // p1 * p2 => p3
code[code[pos+3]] = getParamValue(1, op) * getParamValue(2, op) setParamValue(3, getParamValue(1, op)*getParamValue(2, op), op)
pos += 4 pos += 4
case opCodeTypeInput: // in => p1 case opCodeTypeInput: // in => p1
code[code[pos+1]] = <-in setParamValue(1, <-in, op)
pos += 2 pos += 2
case opCodeTypeOutput: // p1 => out case opCodeTypeOutput: // p1 => out
@ -148,21 +189,25 @@ func executeIntcode(code []int, in, out chan int) ([]int, error) {
pos += 3 pos += 3
case opCodeTypeLessThan: // p1 < p2 => p3 case opCodeTypeLessThan: // p1 < p2 => p3
var res int var res int64
if getParamValue(1, op) < getParamValue(2, op) { if getParamValue(1, op) < getParamValue(2, op) {
res = 1 res = 1
} }
code[code[pos+3]] = res setParamValue(3, res, op)
pos += 4 pos += 4
case opCodeTypeEquals: // p1 == p2 => p3 case opCodeTypeEquals: // p1 == p2 => p3
var res int var res int64
if getParamValue(1, op) == getParamValue(2, op) { if getParamValue(1, op) == getParamValue(2, op) {
res = 1 res = 1
} }
code[code[pos+3]] = res setParamValue(3, res, op)
pos += 4 pos += 4
case opCodeTypeAdjRelBase:
relativeBase += getParamValue(1, op)
pos += 2
case opCodeTypeExit: // exit case opCodeTypeExit: // exit
return code, nil return code, nil

View file

@ -1,9 +1,12 @@
package aoc2019 package aoc2019
import "testing" import (
"reflect"
"testing"
)
func TestParseOpCode(t *testing.T) { func TestParseOpCode(t *testing.T) {
for code, expOpCode := range map[int]opCode{ for code, expOpCode := range map[int64]opCode{
1002: {Type: opCodeTypeMultiplication, flags: []opCodeFlag{opCodeFlagPosition, opCodeFlagImmediate}}, 1002: {Type: opCodeTypeMultiplication, flags: []opCodeFlag{opCodeFlagPosition, opCodeFlagImmediate}},
1101: {Type: opCodeTypeAddition, flags: []opCodeFlag{opCodeFlagImmediate, opCodeFlagImmediate}}, 1101: {Type: opCodeTypeAddition, flags: []opCodeFlag{opCodeFlagImmediate, opCodeFlagImmediate}},
} { } {
@ -17,9 +20,9 @@ func TestExecuteIntcodeIO(t *testing.T) {
code, _ := parseIntcode("3,0,4,0,99") code, _ := parseIntcode("3,0,4,0,99")
var ( var (
exp = 25 exp int64 = 25
in = make(chan int, 1) in = make(chan int64, 1)
out = make(chan int, 1) out = make(chan int64, 1)
) )
in <- exp in <- exp
@ -41,8 +44,8 @@ func TestExecuteIntcodeImmediateFlag(t *testing.T) {
code, _ := parseIntcode("102,4,7,0,4,0,99,3") code, _ := parseIntcode("102,4,7,0,4,0,99,3")
var ( var (
exp = 12 exp int64 = 12
out = make(chan int, 1) out = make(chan int64, 1)
) )
if _, err := executeIntcode(code, nil, out); err != nil { if _, err := executeIntcode(code, nil, out); err != nil {
@ -60,15 +63,15 @@ func TestExecuteIntcodeEquals(t *testing.T) {
"immediate": "3,3,1108,-1,8,3,4,3,99", "immediate": "3,3,1108,-1,8,3,4,3,99",
} { } {
for input, exp := range map[int]int{ for input, exp := range map[int64]int64{
1: 0, 1: 0,
8: 1, 8: 1,
20: 0, 20: 0,
-8: 0, -8: 0,
} { } {
var ( var (
in = make(chan int, 1) in = make(chan int64, 1)
out = make(chan int, 10) out = make(chan int64, 10)
) )
code, _ := parseIntcode(codeStr) code, _ := parseIntcode(codeStr)
@ -93,15 +96,15 @@ func TestExecuteIntcodeLessThan(t *testing.T) {
"immediate": "3,3,1107,-1,8,3,4,3,99", "immediate": "3,3,1107,-1,8,3,4,3,99",
} { } {
for input, exp := range map[int]int{ for input, exp := range map[int64]int64{
1: 1, 1: 1,
8: 0, 8: 0,
20: 0, 20: 0,
-8: 1, -8: 1,
} { } {
var ( var (
in = make(chan int, 1) in = make(chan int64, 1)
out = make(chan int, 10) out = make(chan int64, 10)
) )
code, _ := parseIntcode(codeStr) code, _ := parseIntcode(codeStr)
@ -126,13 +129,13 @@ func TestExecuteIntcodeJump(t *testing.T) {
"immediate": "3,3,1105,-1,9,1101,0,0,12,4,12,99,1", "immediate": "3,3,1105,-1,9,1101,0,0,12,4,12,99,1",
} { } {
for input, exp := range map[int]int{ for input, exp := range map[int64]int64{
5: 1, 5: 1,
0: 0, 0: 0,
} { } {
var ( var (
in = make(chan int, 1) in = make(chan int64, 1)
out = make(chan int, 10) out = make(chan int64, 10)
) )
code, _ := parseIntcode(codeStr) code, _ := parseIntcode(codeStr)
@ -150,3 +153,44 @@ func TestExecuteIntcodeJump(t *testing.T) {
} }
} }
func TestExecuteIntcodeRelativeBase(t *testing.T) {
code, _ := parseIntcode("109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99")
var (
codeCopy []int64
out = make(chan int64, 1)
)
go func() {
if _, err := executeIntcode(code, nil, out); err != nil {
t.Fatalf("Intcode execution failed: %s", err)
}
}()
for v := range out {
codeCopy = append(codeCopy, v)
}
if !reflect.DeepEqual(codeCopy, code) {
t.Errorf("Program yield unexpected result: exp=%d got=%d", code, codeCopy)
}
}
func TestExecuteIntcodeLargeNumber(t *testing.T) {
for codeStr, expValue := range map[string]int64{
"1102,34915192,34915192,7,4,7,99,0": 1219070632396864,
"104,1125899906842624,99": 1125899906842624,
} {
code, _ := parseIntcode(codeStr)
var out = make(chan int64, 1)
if _, err := executeIntcode(code, nil, out); err != nil {
t.Fatalf("Intcode execution failed: %s", err)
}
if r := <-out; r != expValue {
t.Errorf("Execute yield unexpected result: exp=%d got=%d", expValue, r)
}
}
}