From 3300a8bf3e5ade60953cd223160f7aed7903ed69 Mon Sep 17 00:00:00 2001 From: efim Date: Fri, 8 Dec 2023 09:53:26 +0000 Subject: [PATCH] day8, example3 new approach --- day8/dayEight.go | 109 +++++++++++++++++++++++++++++++++++++---------- day8/notes.org | 29 +++++++++++++ 2 files changed, 116 insertions(+), 22 deletions(-) create mode 100644 day8/notes.org diff --git a/day8/dayEight.go b/day8/dayEight.go index aea94d5..00195b6 100644 --- a/day8/dayEight.go +++ b/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 { diff --git a/day8/notes.org b/day8/notes.org new file mode 100644 index 0000000..43d3082 --- /dev/null +++ b/day8/notes.org @@ -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