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

Add solution for Day 16

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2019-12-16 14:56:41 +01:00
parent 3164135e81
commit 41352399f9
Signed by: luzifer
GPG key ID: DC2729FDD34BE99E
3 changed files with 239 additions and 0 deletions

141
day16.go Normal file
View file

@ -0,0 +1,141 @@
package aoc2019
import (
"bytes"
"io/ioutil"
"math"
"strconv"
"strings"
"github.com/pkg/errors"
)
var day16BasePattern = []int64{0, 1, 0, -1}
type day16Pattern struct {
pattern []int64
ptr int
}
func (d *day16Pattern) get() int64 {
d.ptr += 1
if d.ptr == len(d.pattern) {
d.ptr = 0
}
return d.pattern[d.ptr]
}
func day16PatternForElement(idx int) *day16Pattern {
var pattern []int64
for _, p := range day16BasePattern {
for i := 0; i <= idx; i++ {
pattern = append(pattern, p)
}
}
return &day16Pattern{pattern: pattern, ptr: 0}
}
func day16ReadInputSignal(in string) ([]int64, error) {
var out []int64
for _, c := range in {
v, err := strconv.ParseInt(string(c), 10, 64)
if err != nil {
return nil, errors.Wrap(err, "Unable to parse number")
}
out = append(out, v)
}
return out, nil
}
func day16ProcessSignal(s []int64, phases int) []int64 {
var processedSignal = make([]int64, len(s))
copy(processedSignal, s)
for i := 0; i < phases; i++ {
var tmpSignal = make([]int64, len(processedSignal))
for i := range tmpSignal {
p := day16PatternForElement(i)
for _, n := range processedSignal {
tmpSignal[i] += n * p.get()
}
tmpSignal[i] = int64(math.Abs(float64(tmpSignal[i]))) % 10
}
copy(processedSignal, tmpSignal)
}
return processedSignal
}
func solveDay16Part1(inFile string) (string, error) {
raw, err := ioutil.ReadFile(inFile)
if err != nil {
return "", errors.Wrap(err, "Unable to read input file")
}
s, err := day16ReadInputSignal(strings.TrimSpace(string(raw)))
if err != nil {
return "", errors.Wrap(err, "Unable to parse input signal")
}
ps := day16ProcessSignal(s, 100)[:8]
var res string
for _, n := range ps {
res += strconv.FormatInt(n, 10)
}
return res, nil
}
func solveDay16Part2(inFile string) (string, error) {
raw, err := ioutil.ReadFile(inFile)
if err != nil {
return "", errors.Wrap(err, "Unable to read input file")
}
raw = bytes.TrimSpace(raw)
// Assemble "real signal"
rs := make([]byte, 10000*len(raw))
for i := 0; i < 10000; i++ {
copy(rs[i*len(raw):(i+1)*len(raw)], raw)
}
offset, err := strconv.ParseInt(string(raw[0:7]), 10, 64)
if err != nil {
return "", errors.Wrap(err, "Unable to parse offset")
}
rs = rs[offset:]
s, err := day16ReadInputSignal(string(rs))
if err != nil {
return "", errors.Wrap(err, "Unable to parse input signal")
}
// Calculate special solution for offset-trimmed signal
for phase := 0; phase < 100; phase++ {
for i := len(s) - 1; i >= 0; i-- {
var ni int64
if i+1 < len(s) {
ni = s[i+1]
}
s[i] = int64(math.Abs(float64(ni+s[i]))) % 10
}
}
// Marshal output
var res string
for _, n := range s[:8] {
res += strconv.FormatInt(n, 10)
}
return res, nil
}

1
day16_input.txt Normal file
View file

@ -0,0 +1 @@
59773419794631560412886746550049210714854107066028081032096591759575145680294995770741204955183395640103527371801225795364363411455113236683168088750631442993123053909358252440339859092431844641600092736006758954422097244486920945182483159023820538645717611051770509314159895220529097322723261391627686997403783043710213655074108451646685558064317469095295303320622883691266307865809481566214524686422834824930414730886697237161697731339757655485312568793531202988525963494119232351266908405705634244498096660057021101738706453735025060225814133166491989584616948876879383198021336484629381888934600383957019607807995278899293254143523702000576897358

97
day16_test.go Normal file
View file

@ -0,0 +1,97 @@
package aoc2019
import (
"reflect"
"testing"
)
func TestDay16TestPatternForElement(t *testing.T) {
for idx, expPattern := range [][]int64{
{0, 1, 0, -1},
{0, 0, 1, 1, 0, 0, -1, -1},
{0, 0, 0, 1, 1, 1, 0, 0, 0, -1, -1, -1},
} {
if p := day16PatternForElement(idx); !reflect.DeepEqual(expPattern, p.pattern) {
t.Errorf("Unexpected pattern for idx=%d: exp=%+v got=%+v", idx, expPattern, p.pattern)
}
}
}
func TestDay16PatternLoop(t *testing.T) {
p1 := day16PatternForElement(0)
for i, expN := range []int64{
// MUST skip first element at first execution
// 0,
1, 0, -1, 0, 1, 0, -1, 0, 1, 0, -1,
} {
if n := p1.get(); n != expN {
t.Errorf("Unexpected number for pattern p1 at index %d: exp=%d got=%d", i, expN, n)
}
}
}
func TestDay16ParseInputSignal(t *testing.T) {
s, err := day16ReadInputSignal("12345678")
if err != nil {
t.Fatalf("Unable to parse input signal: %s", err)
}
if !reflect.DeepEqual(s, []int64{1, 2, 3, 4, 5, 6, 7, 8}) {
t.Errorf("Unexpected input signal: %+v", s)
}
}
func TestDay16ProcessSignal(t *testing.T) {
s, err := day16ReadInputSignal("12345678")
if err != nil {
t.Fatalf("Unable to parse input signal: %s", err)
}
for i, expS := range [][]int64{
{1, 2, 3, 4, 5, 6, 7, 8},
{4, 8, 2, 2, 6, 1, 5, 8},
{3, 4, 0, 4, 0, 4, 3, 8},
{0, 3, 4, 1, 5, 5, 1, 8},
{0, 1, 0, 2, 9, 4, 9, 8},
} {
if rs := day16ProcessSignal(s, i); !reflect.DeepEqual(rs, expS) {
t.Errorf("Unexpected processed signal after %d phases: exp=%+v got=%+v", i, expS, rs)
}
}
}
func TestDay16ProcessSignal8OfLonger(t *testing.T) {
for signal, expPSig8 := range map[string][]int64{
"80871224585914546619083218645595": {2, 4, 1, 7, 6, 1, 7, 6},
"19617804207202209144916044189917": {7, 3, 7, 4, 5, 4, 1, 8},
"69317163492948606335995924319873": {5, 2, 4, 3, 2, 1, 3, 3},
} {
s, err := day16ReadInputSignal(signal)
if err != nil {
t.Fatalf("Unable to parse input signal %q: %s", signal, err)
}
if rs := day16ProcessSignal(s, 100); !reflect.DeepEqual(rs[:8], expPSig8) {
t.Errorf("Unexpected processed signal for signal %q: exp=%+v got=%+v", signal, expPSig8, rs[:8])
}
}
}
func TestCalculateDay16_Part1(t *testing.T) {
res, err := solveDay16Part1("day16_input.txt")
if err != nil {
t.Fatalf("Day 16 solver failed: %s", err)
}
t.Logf("Solution Day 16 Part 1: %s", res)
}
func TestCalculateDay16_Part2(t *testing.T) {
res, err := solveDay16Part2("day16_input.txt")
if err != nil {
t.Fatalf("Day 16 solver failed: %s", err)
}
t.Logf("Solution Day 16 Part 2: %s", res)
}