mirror of
https://github.com/Luzifer/aoc2019.git
synced 2024-12-21 21:41: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