243 lines
5.1 KiB
Go
243 lines
5.1 KiB
Go
package day23
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
type Lan struct {
|
|
nodes []*Node
|
|
}
|
|
|
|
type Node struct {
|
|
key string
|
|
adjacent []*Node
|
|
loops [][]*Node
|
|
}
|
|
|
|
func Part1(input string) int {
|
|
total := 0
|
|
|
|
lan := &Lan{}
|
|
|
|
pattern := `^([a-z]{2})-([a-z]{2})$`
|
|
re := regexp.MustCompile(pattern)
|
|
lines := strings.Split(input, "\n")
|
|
for _, line := range lines {
|
|
matches := re.FindAllStringSubmatch(line, -1)
|
|
for _, match := range matches {
|
|
lan.AddNode(match[1])
|
|
lan.AddNode(match[2])
|
|
lan.AddConnection(match[1], match[2])
|
|
lan.AddConnection(match[2], match[1])
|
|
}
|
|
}
|
|
for _, node := range lan.nodes {
|
|
if node.key[0] == 't' {
|
|
connections := node.adjacent
|
|
for _, connection := range connections {
|
|
c := lan.getNode(connection.key)
|
|
for _, n1 := range c.adjacent {
|
|
for _, n2 := range connections {
|
|
if n1.key == n2.key {
|
|
already_found := false
|
|
for _, loop := range node.loops {
|
|
if contains(loop, c.key) && contains(loop, n2.key) {
|
|
already_found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
for _, loop := range c.loops {
|
|
if contains(loop, node.key) && contains(loop, n2.key) {
|
|
already_found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
for _, loop := range n2.loops {
|
|
if contains(loop, c.key) && contains(loop, node.key) {
|
|
already_found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !already_found {
|
|
already_found = true
|
|
total++
|
|
loop := make([]*Node, 0)
|
|
loop = append(loop, node)
|
|
loop = append(loop, c)
|
|
loop = append(loop, n2)
|
|
node.loops = append(node.loops, loop)
|
|
fmt.Printf("%v,%v,%v\n", node.key, c.key, n2.key)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
lan.Print()
|
|
t := 0
|
|
for _, node := range lan.nodes {
|
|
if node.key[0] == 't' {
|
|
t += len(node.loops)
|
|
fmt.Printf("Node: %v\n", node.key)
|
|
for _, loop := range node.loops {
|
|
for _, n := range loop {
|
|
fmt.Printf(" %v ", n.key)
|
|
}
|
|
fmt.Println()
|
|
}
|
|
}
|
|
}
|
|
fmt.Printf("Total: %d\n", t)
|
|
return total
|
|
}
|
|
|
|
func Part2(input string) int {
|
|
total := 0
|
|
|
|
lan := &Lan{}
|
|
|
|
pattern := `^([a-z]{2})-([a-z]{2})$`
|
|
re := regexp.MustCompile(pattern)
|
|
lines := strings.Split(input, "\n")
|
|
for _, line := range lines {
|
|
matches := re.FindAllStringSubmatch(line, -1)
|
|
for _, match := range matches {
|
|
lan.AddNode(match[1])
|
|
lan.AddNode(match[2])
|
|
lan.AddConnection(match[1], match[2])
|
|
lan.AddConnection(match[2], match[1])
|
|
}
|
|
}
|
|
for _, node := range lan.nodes {
|
|
connections := node.adjacent
|
|
for _, connection := range connections {
|
|
c := lan.getNode(connection.key)
|
|
for _, n1 := range c.adjacent {
|
|
for _, n2 := range connections {
|
|
if n1.key == n2.key {
|
|
already_found := false
|
|
for _, loop := range node.loops {
|
|
if contains(loop, c.key) && contains(loop, n2.key) {
|
|
already_found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
for _, loop := range c.loops {
|
|
if contains(loop, node.key) && contains(loop, n2.key) {
|
|
already_found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
for _, loop := range n2.loops {
|
|
if contains(loop, c.key) && contains(loop, node.key) {
|
|
already_found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !already_found {
|
|
already_found = true
|
|
total++
|
|
loop := make([]*Node, 0)
|
|
loop = append(loop, node)
|
|
loop = append(loop, c)
|
|
loop = append(loop, n2)
|
|
node.loops = append(node.loops, loop)
|
|
fmt.Printf("%v,%v,%v\n", node.key, c.key, n2.key)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
lan.Print()
|
|
maxLoop := 0
|
|
var maxNode *Node
|
|
for _, node := range lan.nodes {
|
|
if len(node.loops) > maxLoop {
|
|
maxLoop = len(node.loops)
|
|
maxNode = node
|
|
}
|
|
}
|
|
fmt.Printf("Max: %d\n", len(maxNode.loops))
|
|
nodeList := make([]*Node, 0)
|
|
keyList := make([]string, 0)
|
|
for _, loop := range maxNode.loops {
|
|
for _, l := range loop {
|
|
if !contains(nodeList, l.key) {
|
|
nodeList = append(nodeList, l)
|
|
keyList = append(keyList, l.key)
|
|
}
|
|
}
|
|
}
|
|
sort.Strings(keyList)
|
|
fmt.Println(strings.Join(keyList, ","))
|
|
return len(nodeList)
|
|
}
|
|
|
|
func (g *Lan) AddNode(key string) {
|
|
if !contains(g.nodes, key) {
|
|
g.nodes = append(g.nodes, &Node{key: key})
|
|
}
|
|
}
|
|
|
|
func (g *Lan) AddConnection(from, to string) {
|
|
fromNode := g.getNode(from)
|
|
toNode := g.getNode(to)
|
|
|
|
if fromNode == nil || toNode == nil {
|
|
err := fmt.Errorf("Error: Invalid edge (%v --> %v)", from, to)
|
|
fmt.Println(err.Error())
|
|
} else if contains(fromNode.adjacent, to) {
|
|
err := fmt.Errorf("Error: Existing edge (%v --> %v)", from, to)
|
|
fmt.Println(err.Error())
|
|
} else {
|
|
fromNode.adjacent = append(fromNode.adjacent, toNode)
|
|
}
|
|
}
|
|
|
|
func (g *Lan) getNode(key string) *Node {
|
|
for i, v := range g.nodes {
|
|
if v.key == key {
|
|
return g.nodes[i]
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (g *Lan) Print() {
|
|
for _, v := range g.nodes {
|
|
fmt.Printf("\nNode %v : ", v.key)
|
|
for _, v := range v.adjacent {
|
|
fmt.Printf(" %v ", v.key)
|
|
}
|
|
fmt.Println()
|
|
for _, loop := range v.loops {
|
|
for _, v := range loop {
|
|
if v != nil {
|
|
fmt.Printf(" %v ", v.key)
|
|
}
|
|
}
|
|
fmt.Println()
|
|
}
|
|
}
|
|
}
|
|
|
|
func contains(list []*Node, key string) bool {
|
|
for _, v := range list {
|
|
if key == v.key {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|