mirror of
https://github.com/Luzifer/aoc2019.git
synced 2024-12-22 05:51:16 +00:00
Add solution for Day 16
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
3164135e81
commit
41352399f9
3 changed files with 239 additions and 0 deletions
141
day16.go
Normal file
141
day16.go
Normal 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
1
day16_input.txt
Normal file
|
@ -0,0 +1 @@
|
|||
59773419794631560412886746550049210714854107066028081032096591759575145680294995770741204955183395640103527371801225795364363411455113236683168088750631442993123053909358252440339859092431844641600092736006758954422097244486920945182483159023820538645717611051770509314159895220529097322723261391627686997403783043710213655074108451646685558064317469095295303320622883691266307865809481566214524686422834824930414730886697237161697731339757655485312568793531202988525963494119232351266908405705634244498096660057021101738706453735025060225814133166491989584616948876879383198021336484629381888934600383957019607807995278899293254143523702000576897358
|
97
day16_test.go
Normal file
97
day16_test.go
Normal 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)
|
||||
}
|
Loading…
Reference in a new issue