package main
import (
"bufio"
"fmt"
"log"
"os"
"strings"
)
type Graph struct {
Satellites []string
Orbits map[string][]string
}
func (g *Graph) Add(a, b string) {
found := false
for _, aa := range g.Satellites {
if aa == a {
found = true
}
}
if !found {
g.Satellites = append(g.Satellites, a)
}
if g.Orbits == nil {
g.Orbits = make(map[string][]string)
}
g.Orbits[a] = append(g.Orbits[a], b)
}
func (g Graph) String() string {
result := ""
for _, a := range g.Satellites {
result += fmt.Sprintf("%s ->", a)
if _, ok := g.Orbits[a]; ok {
for _, b := range g.Orbits[a] {
result += fmt.Sprintf(" %s", b)
}
}
result += fmt.Sprintf("\n")
}
return result
}
func CountOrbits(g Graph, a string, fromRoot int) int {
indirect := fromRoot
if _, ok := g.Orbits[a]; ok {
for _, b := range g.Orbits[a] {
indirect += CountOrbits(g, b, fromRoot+1)
}
}
return indirect
}
func findNode(g Graph, parent, target string) ([]string, bool) {
if parent == target {
return nil, true
}
for _, a := range g.Orbits[parent] {
if v, found := findNode(g, a, target); found {
return append(v, a), found
}
}
return nil, false
}
func CalcTransfers(g Graph, a, b string) int {
aMoves, _ := findNode(g, "COM", a)
bMoves, _ := findNode(g, "COM", b)
for i, a := range aMoves {
for j, b := range bMoves {
if a == b {
return i + j - 2
}
}
}
return -1
}
func main() {
input, err := os.Open("input.txt")
if err != nil {
log.Fatal(fmt.Errorf("could not open input file: %w", err))
}
defer input.Close()
var system Graph
scanner := bufio.NewScanner(input)
for scanner.Scan() {
var orbit string
fmt.Sscanf(scanner.Text(), "%s", &orbit)
o := strings.Split(orbit, ")")
system.Add(o[0], o[1])
}
if err := scanner.Err(); err != nil {
log.Fatal(fmt.Errorf("error while scanning input: %w", err))
}
fmt.Printf("Part 1: %d\n", CountOrbits(system, "COM", 0))
fmt.Printf("Part 2: %d\n", CalcTransfers(system, "YOU", "SAN"))
}