1
0
Fork 0
mirror of https://github.com/Luzifer/aoc2019.git synced 2024-12-22 05:51:16 +00:00

Add solution for Day 6

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2019-12-06 14:21:19 +01:00
parent 658829657b
commit df8eec9d2e
Signed by: luzifer
GPG key ID: DC2729FDD34BE99E
3 changed files with 1354 additions and 0 deletions

128
day06.go Normal file
View file

@ -0,0 +1,128 @@
package aoc2019
import (
"bufio"
"io"
"os"
"strings"
"github.com/pkg/errors"
)
type day06Planet struct {
Name string
Orbits *day06Planet
}
func (d *day06Planet) getPathLengthToPlanet(tp *day06Planet) int {
if d == tp {
return 0
}
return 1 + d.Orbits.getPathLengthToPlanet(tp)
}
type day06OrbitMap map[string]*day06Planet
func (d day06OrbitMap) getPathLengthToCOMByName(start string) int {
return d[start].getPathLengthToPlanet(d["COM"])
}
func (d day06OrbitMap) getCommonPlanet(a, b *day06Planet) *day06Planet {
var (
pathAToCOM, pathBToCOM []*day06Planet
ptr *day06Planet
)
// Get path A
ptr = a
for {
pathAToCOM = append(pathAToCOM, ptr)
if ptr.Orbits == nil {
break
}
ptr = ptr.Orbits
}
// Get path B
ptr = b
for {
pathBToCOM = append(pathBToCOM, ptr)
if ptr.Orbits == nil {
break
}
ptr = ptr.Orbits
}
// Find first common planet
for _, ptrA := range pathAToCOM {
for _, ptrB := range pathBToCOM {
if ptrA == ptrB {
return ptrA
}
}
}
return nil
}
func day06ParseOrbitMap(localMap io.Reader) (day06OrbitMap, error) {
m := day06OrbitMap{}
scanner := bufio.NewScanner(localMap)
for scanner.Scan() {
if err := scanner.Err(); err != nil {
return nil, errors.Wrap(err, "Scanner failed to scan")
}
parts := strings.Split(scanner.Text(), ")")
for _, p := range parts {
if _, ok := m[p]; !ok {
m[p] = &day06Planet{Name: p}
}
}
m[parts[1]].Orbits = m[parts[0]]
}
return m, nil
}
func solveDay6Part1(inFile string) (int, error) {
f, err := os.Open(inFile)
if err != nil {
return 0, errors.Wrap(err, "Unable to open input file")
}
defer f.Close()
oMap, err := day06ParseOrbitMap(f)
if err != nil {
return 0, errors.Wrap(err, "Unable to parse orbit map")
}
var c int
for _, p := range oMap {
c += p.getPathLengthToPlanet(oMap["COM"])
}
return c, nil
}
func solveDay6Part2(inFile string) (int, error) {
f, err := os.Open(inFile)
if err != nil {
return 0, errors.Wrap(err, "Unable to open input file")
}
defer f.Close()
oMap, err := day06ParseOrbitMap(f)
if err != nil {
return 0, errors.Wrap(err, "Unable to parse orbit map")
}
cp := oMap.getCommonPlanet(oMap["YOU"], oMap["SAN"])
dist := oMap["YOU"].getPathLengthToPlanet(cp) + oMap["SAN"].getPathLengthToPlanet(cp)
// Distance is 2 too high as we're not a planet but a ship cycling a planet: Close enough
return dist - 2, nil
}

1153
day06_input.txt Normal file

File diff suppressed because it is too large Load diff

73
day06_test.go Normal file
View file

@ -0,0 +1,73 @@
package aoc2019
import (
"strings"
"testing"
)
var day06OrbitMapExample = strings.TrimSpace(`
COM)B
B)C
C)D
D)E
E)F
B)G
G)H
D)I
E)J
J)K
K)L
K)YOU
I)SAN
`)
func TestDay6OrbitPathLengthToCOM(t *testing.T) {
oMap, err := day06ParseOrbitMap(strings.NewReader(day06OrbitMapExample))
if err != nil {
t.Fatalf("Orbit map parser failed: %s", err)
}
for start, expCount := range map[string]int{
"D": 3,
"L": 7,
"COM": 0,
} {
if c := oMap.getPathLengthToCOMByName(start); c != expCount {
t.Errorf("Number of recursive orbits to %q yield unexpected result: exp=%d got=%d", start, expCount, c)
}
}
}
func TestDay6OrbitMapCommonPlanet(t *testing.T) {
oMap, err := day06ParseOrbitMap(strings.NewReader(day06OrbitMapExample))
if err != nil {
t.Fatalf("Orbit map parser failed: %s", err)
}
p := oMap.getCommonPlanet(oMap["YOU"], oMap["SAN"])
if p == nil {
t.Fatalf("Found no common planet")
}
if p != oMap["D"] {
t.Errorf("Found wrong common planet: exp=D, got=%s", p.Name)
}
}
func TestCalculateDay6_Part1(t *testing.T) {
count, err := solveDay6Part1("day06_input.txt")
if err != nil {
t.Fatalf("Day 6 solver failed: %s", err)
}
t.Logf("Solution Day 6 Part 1: %d", count)
}
func TestCalculateDay6_Part2(t *testing.T) {
count, err := solveDay6Part2("day06_input.txt")
if err != nil {
t.Fatalf("Day 6 solver failed: %s", err)
}
t.Logf("Solution Day 6 Part 2: %d", count)
}