mirror of
https://github.com/Luzifer/aoc2019.git
synced 2024-12-22 05:51:16 +00:00
Add solution for Day 7
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
c4133300d0
commit
90216aba66
4 changed files with 202 additions and 0 deletions
102
day07.go
Normal file
102
day07.go
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
package aoc2019
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func day07TestMaxOutputFromChain(code []int, chainStart, chainEnd int, looped bool) int {
|
||||||
|
var (
|
||||||
|
chainLen = chainEnd - chainStart + 1
|
||||||
|
permuts [][]int
|
||||||
|
permute func(a []int, k int)
|
||||||
|
rootSeq = make([]int, chainLen)
|
||||||
|
)
|
||||||
|
|
||||||
|
permute = func(a []int, k int) {
|
||||||
|
if k == len(a) {
|
||||||
|
permuts = append(permuts, append([]int{}, a...))
|
||||||
|
} else {
|
||||||
|
for i := k; i < len(rootSeq); i++ {
|
||||||
|
a[k], a[i] = a[i], a[k]
|
||||||
|
permute(a, k+1)
|
||||||
|
a[k], a[i] = a[i], a[k]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range rootSeq {
|
||||||
|
rootSeq[i] = chainStart + i
|
||||||
|
}
|
||||||
|
permute(rootSeq, 0)
|
||||||
|
|
||||||
|
var maxOutput int
|
||||||
|
for _, seq := range permuts {
|
||||||
|
var (
|
||||||
|
commInChans = make([]chan int, chainLen)
|
||||||
|
commOut = make(chan int, 2)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Create channels
|
||||||
|
for i := range commInChans {
|
||||||
|
commInChans[i] = make(chan int, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build execution chain
|
||||||
|
for i := 0; i < chainLen-1; i++ {
|
||||||
|
go executeIntcode(cloneIntcode(code), commInChans[i], commInChans[i+1])
|
||||||
|
}
|
||||||
|
go executeIntcode(cloneIntcode(code), commInChans[chainLen-1], commOut)
|
||||||
|
|
||||||
|
// Initialize chain
|
||||||
|
for i, v := range seq {
|
||||||
|
commInChans[i] <- v
|
||||||
|
}
|
||||||
|
commInChans[0] <- 0 // Input signal
|
||||||
|
|
||||||
|
var lastOutput int
|
||||||
|
for r := range commOut {
|
||||||
|
lastOutput = r
|
||||||
|
if looped {
|
||||||
|
commInChans[0] <- r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test output of last execution
|
||||||
|
if lastOutput > maxOutput {
|
||||||
|
maxOutput = lastOutput
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxOutput
|
||||||
|
}
|
||||||
|
|
||||||
|
func solveDay7Part1(inFile string) (int, 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")
|
||||||
|
}
|
||||||
|
|
||||||
|
return day07TestMaxOutputFromChain(code, 0, 4, false), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func solveDay7Part2(inFile string) (int, 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")
|
||||||
|
}
|
||||||
|
|
||||||
|
return day07TestMaxOutputFromChain(code, 5, 9, true), nil
|
||||||
|
}
|
1
day07_input.txt
Normal file
1
day07_input.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
3,8,1001,8,10,8,105,1,0,0,21,46,59,84,93,102,183,264,345,426,99999,3,9,1002,9,4,9,1001,9,3,9,102,2,9,9,1001,9,5,9,102,3,9,9,4,9,99,3,9,1002,9,3,9,101,4,9,9,4,9,99,3,9,1002,9,4,9,1001,9,4,9,102,2,9,9,1001,9,2,9,1002,9,3,9,4,9,99,3,9,1001,9,5,9,4,9,99,3,9,1002,9,4,9,4,9,99,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,9,1,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1002,9,2,9,4,9,99,3,9,101,1,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,1,9,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,101,1,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,99,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,1,9,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,1,9,4,9,99,3,9,101,1,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,101,1,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,101,1,9,9,4,9,3,9,101,1,9,9,4,9,99
|
91
day07_test.go
Normal file
91
day07_test.go
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
package aoc2019
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestChainedInput(t *testing.T) {
|
||||||
|
code, err := parseIntcode("3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Intcode parser failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create channels
|
||||||
|
var (
|
||||||
|
aIn = make(chan int, 2)
|
||||||
|
bIn = make(chan int, 2)
|
||||||
|
cIn = make(chan int, 2)
|
||||||
|
dIn = make(chan int, 2)
|
||||||
|
eIn = make(chan int, 2)
|
||||||
|
eOut = make(chan int, 2)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Build execution chain
|
||||||
|
go executeIntcode(cloneIntcode(code), aIn, bIn)
|
||||||
|
go executeIntcode(cloneIntcode(code), bIn, cIn)
|
||||||
|
go executeIntcode(cloneIntcode(code), cIn, dIn)
|
||||||
|
go executeIntcode(cloneIntcode(code), dIn, eIn)
|
||||||
|
go executeIntcode(cloneIntcode(code), eIn, eOut)
|
||||||
|
|
||||||
|
// Initialize chain
|
||||||
|
aIn <- 4 // Sequence
|
||||||
|
aIn <- 0 // Input signal
|
||||||
|
bIn <- 3 // Sequence
|
||||||
|
cIn <- 2 // Sequence
|
||||||
|
dIn <- 1 // Sequence
|
||||||
|
eIn <- 0 // Sequence
|
||||||
|
|
||||||
|
// Test output of last execution
|
||||||
|
if r := <-eOut; r != 43210 {
|
||||||
|
t.Errorf("Unexpected result from chain: exp=43210 got=%d", r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMaxOutputFromChain(t *testing.T) {
|
||||||
|
for codeStr, expValue := range map[string]int{
|
||||||
|
"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,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,
|
||||||
|
} {
|
||||||
|
code, err := parseIntcode(codeStr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Parsing Intcode failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r := day07TestMaxOutputFromChain(code, 0, 4, false); r != expValue {
|
||||||
|
t.Errorf("Max output yield unexpected result: exp=%d got=%d", expValue, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMaxOutputFromLoopedChain(t *testing.T) {
|
||||||
|
for codeStr, expValue := range map[string]int{
|
||||||
|
"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,
|
||||||
|
} {
|
||||||
|
code, err := parseIntcode(codeStr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Parsing Intcode failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r := day07TestMaxOutputFromChain(code, 5, 9, true); r != expValue {
|
||||||
|
t.Errorf("Max output yield unexpected result: exp=%d got=%d", expValue, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCalculateDay7_Part1(t *testing.T) {
|
||||||
|
codeP0, err := solveDay7Part1("day07_input.txt")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Day 7 solver failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Solution Day 7 Part 1: %d", codeP0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCalculateDay7_Part2(t *testing.T) {
|
||||||
|
result, err := solveDay7Part2("day07_input.txt")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Day 7 solver failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Solution Day 7 Part 2: %d", result)
|
||||||
|
}
|
|
@ -63,6 +63,14 @@ func parseOpCode(in int) opCode {
|
||||||
return out
|
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) {
|
func parseIntcode(code string) ([]int, error) {
|
||||||
parts := strings.Split(code, ",")
|
parts := strings.Split(code, ",")
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue