day8, example3 new approach

This commit is contained in:
efim
2023-12-08 09:53:26 +00:00
parent dea9d15c66
commit 3300a8bf3e
2 changed files with 116 additions and 22 deletions

View File

@@ -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 {