day8, example3 new approach
This commit is contained in:
parent
dea9d15c66
commit
3300a8bf3e
109
day8/dayEight.go
109
day8/dayEight.go
|
@ -18,8 +18,7 @@ func Run() int {
|
|||
return result
|
||||
}
|
||||
|
||||
func GhostTraverse(net Network, path Path) int {
|
||||
stepsNum := 0
|
||||
func getGhostStartNodes(net Network) []Node {
|
||||
simultaneousPaths := make([]Node, 0)
|
||||
for nodeName, node := range net.Nodes {
|
||||
if strings.HasSuffix(nodeName, "A") {
|
||||
|
@ -27,28 +26,94 @@ func GhostTraverse(net Network, path Path) int {
|
|||
}
|
||||
}
|
||||
log.Printf("collected start points: %+v\n", simultaneousPaths)
|
||||
|
||||
// concurrent iteraction
|
||||
for !isGhostWayDone(simultaneousPaths) {
|
||||
direction := path.next()
|
||||
for i, curNode := range simultaneousPaths {
|
||||
simultaneousPaths[i] = getNextNode(net, curNode, direction)
|
||||
}
|
||||
// log.Printf("done step into %+v\n", simultaneousPaths)
|
||||
stepsNum += 1
|
||||
}
|
||||
|
||||
return stepsNum
|
||||
return simultaneousPaths
|
||||
}
|
||||
|
||||
func isGhostWayDone(simulaneousPath []Node) bool {
|
||||
containsNonZEnding := slices.ContainsFunc(simulaneousPath, func(curNode Node) bool {
|
||||
name := curNode.Name
|
||||
last := name[len(name) - 1]
|
||||
return last != 'Z'
|
||||
})
|
||||
// log.Printf("checking if done for %+v : %t", simulaneousPath, !containsNonZEnding)
|
||||
return !containsNonZEnding
|
||||
type GhostPathInfo struct {
|
||||
InitialSteps, CycleLen int
|
||||
}
|
||||
|
||||
func getGhostPathInfo(startNode Node, net Network, pathString string) GhostPathInfo {
|
||||
path := Path {Instruction: pathString}
|
||||
initialSteps, cycleLen := 0, 1
|
||||
runnerNode := startNode
|
||||
|
||||
for !strings.HasSuffix(runnerNode.Name, "Z") {
|
||||
direction := path.next()
|
||||
runnerNode = getNextNode(net, runnerNode, direction)
|
||||
initialSteps += 1
|
||||
}
|
||||
// one more step for starting to check for cycle
|
||||
oneDirection := path.next()
|
||||
runnerNode = getNextNode(net, runnerNode, oneDirection)
|
||||
|
||||
for !strings.HasSuffix(runnerNode.Name, "Z") {
|
||||
direction := path.next()
|
||||
runnerNode = getNextNode(net, runnerNode, direction)
|
||||
cycleLen += 1
|
||||
}
|
||||
|
||||
return GhostPathInfo{
|
||||
InitialSteps: initialSteps,
|
||||
CycleLen: cycleLen,
|
||||
}
|
||||
}
|
||||
|
||||
func GhostTraverse(net Network, path Path) int {
|
||||
simultaneousPaths := getGhostStartNodes(net)
|
||||
pathInfos := make([]GhostPathInfo, 0, len(simultaneousPaths))
|
||||
for _, pathStart := range simultaneousPaths {
|
||||
pathInfos = append(pathInfos, getGhostPathInfo(pathStart, net, path.Instruction))
|
||||
}
|
||||
log.Printf("path infos are %+v\n", pathInfos)
|
||||
|
||||
// and now the algo.
|
||||
// if initial paths equal - that's answer
|
||||
// if not - seed round, +1 cycle to each
|
||||
// if equal - that the answer
|
||||
// if not - here's the main loop
|
||||
// find biggest.
|
||||
// then iterate all but that one.
|
||||
// calculate diff % curCycle. if == 0, just add to where they stand together
|
||||
// if not - add cycles to this with one overhopping
|
||||
// and check whether they are all equeal
|
||||
|
||||
stepCounts := make([]int, len(pathInfos))
|
||||
for i, pathInfo := range pathInfos {
|
||||
stepCounts[i] = pathInfo.InitialSteps
|
||||
}
|
||||
|
||||
// oh, i don't need to seed the cycle, they are already not equal
|
||||
for !allEqual(stepCounts) {
|
||||
max := slices.Max(stepCounts)
|
||||
for i, pathInfo := range pathInfos {
|
||||
steps := stepCounts[i]
|
||||
if steps == max {
|
||||
continue
|
||||
}
|
||||
diff := max - steps
|
||||
isCatchingUp := diff % pathInfo.CycleLen == 0
|
||||
if isCatchingUp {
|
||||
stepCounts[i] = max
|
||||
} else {
|
||||
overJump := (diff / pathInfo.CycleLen + 1) * pathInfo.CycleLen
|
||||
stepCounts[i] += overJump
|
||||
}
|
||||
}
|
||||
log.Printf("done one cycle iteration, results : %+v", stepCounts)
|
||||
}
|
||||
|
||||
return stepCounts[0]
|
||||
}
|
||||
|
||||
func allEqual(nums []int) bool {
|
||||
head := nums[0]
|
||||
for _, num := range nums {
|
||||
if num != head {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func getNextNode(net Network, curNode Node, direction rune) Node {
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
#+title: Notes
|
||||
* ok, for part 2 i think i'm supposed to find cicles.
|
||||
so for each starting point?
|
||||
calculate how long it takes to get to first Z, let's call is initialN
|
||||
and then how long it takes to get to Z again, call it cicleN
|
||||
|
||||
i have initial0 + n0 * cicle0 = k
|
||||
|
||||
now i need to find minimal number K ( steps ), so that exists solution for each starting point
|
||||
|
||||
(k - initial0) % cycle0 == 0
|
||||
|
||||
so. get both these numbers for each starting point.
|
||||
if initialN are equal, that's the answer.
|
||||
|
||||
if they are not equal?
|
||||
then i have what? huh
|
||||
|
||||
i guess then i need to add 1 cycle length to all.
|
||||
if they are equal, nice.
|
||||
|
||||
but if they are not equal?
|
||||
i guess i have one that's longest?
|
||||
then i need to advance all paths, up to and overshoot if necessary by their cycle lengths.
|
||||
so take the difference, if divisible by cycle - yay. just multiply, if not divisible - overshoot with +1 cycle
|
||||
|
||||
if all are same, that's solution.
|
||||
if one is farthest, repeat
|
||||
* i stopped bruteforce at 4080000000
|
Loading…
Reference in New Issue