-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnodes.go
153 lines (120 loc) · 2.83 KB
/
nodes.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package day08
import (
"github.com/user3690/advent-of-code-in-go/util"
"log"
"strings"
)
type instruction uint8
type node struct {
name string
left string
right string
}
const (
left instruction = iota
right
)
func BothParts() (uint64, int) {
var (
lines []string
instructions []instruction
nodes map[string]node
steps uint64
stepsAsGhost []int
err error
)
lines, err = util.ReadFileInLines("./2023/day08/input.txt")
if err != nil {
log.Fatal(err)
}
instructions, nodes = prepareData(lines)
if err != nil {
log.Fatal(err)
}
steps = countSteps(instructions, nodes)
stepsAsGhost = countStepsAsGhost(instructions, nodes)
overallSteps := util.LCM(stepsAsGhost[0], stepsAsGhost[1], stepsAsGhost...)
return steps, overallSteps
}
func prepareData(lines []string) ([]instruction, map[string]node) {
var (
instructions = make([]instruction, len(lines[0]))
nodes = make(map[string]node)
)
for i, letter := range lines[0] {
if letter == 'R' {
instructions[i] = right
} else {
instructions[i] = left
}
}
for _, line := range lines[1:] {
newNode := node{}
splitLine := strings.Split(line, "=")
newNode.name = strings.TrimSpace(splitLine[0])
replacer := strings.NewReplacer("(", "", ")", "", ",", "")
nodeNames := replacer.Replace(splitLine[1])
splitNodeNames := strings.Split(strings.TrimSpace(nodeNames), " ")
newNode.left = splitNodeNames[0]
newNode.right = splitNodeNames[1]
nodes[newNode.name] = newNode
}
return instructions, nodes
}
func countSteps(instructions []instruction, nodes map[string]node) (steps uint64) {
var nextNode, end node
nextNode = nodes["AAA"]
end = nodes["ZZZ"]
for i := 0; i < len(instructions); i++ {
if nextNode == end {
break
}
if instructions[i] == left {
nextNode = nodes[nextNode.left]
} else {
nextNode = nodes[nextNode.right]
}
steps++
// reset loop
if i == len(instructions)-1 {
i = -1
}
}
return steps
}
// countStepsAsGhost the assumption is that the first found ending, is also the correct ending.
// The input file is constructed that way, otherwise this shouldn't work.
func countStepsAsGhost(instructions []instruction, nodes map[string]node) []int {
var (
curNodes []node
allSteps []int
steps int
)
for _, curNode := range nodes {
index := strings.LastIndexAny(curNode.name, "A")
if index == 2 {
curNodes = append(curNodes, curNode)
}
}
allSteps = make([]int, len(curNodes))
for i, curNode := range curNodes {
steps = 0
for j := 0; j < len(instructions); j++ {
if curNode.name[2] == 'Z' {
break
}
if instructions[j] == left {
curNode = nodes[curNode.left]
} else {
curNode = nodes[curNode.right]
}
steps++
// reset loop
if j == len(instructions)-1 {
j = -1
}
}
allSteps[i] = steps
}
return allSteps
}