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:
parent
658829657b
commit
df8eec9d2e
3 changed files with 1354 additions and 0 deletions
128
day06.go
Normal file
128
day06.go
Normal 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
1153
day06_input.txt
Normal file
File diff suppressed because it is too large
Load diff
73
day06_test.go
Normal file
73
day06_test.go
Normal 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)
|
||||||
|
}
|
Loading…
Reference in a new issue