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 return result
} }
func GhostTraverse(net Network, path Path) int { func getGhostStartNodes(net Network) []Node {
stepsNum := 0
simultaneousPaths := make([]Node, 0) simultaneousPaths := make([]Node, 0)
for nodeName, node := range net.Nodes { for nodeName, node := range net.Nodes {
if strings.HasSuffix(nodeName, "A") { if strings.HasSuffix(nodeName, "A") {
@ -27,28 +26,94 @@ func GhostTraverse(net Network, path Path) int {
} }
} }
log.Printf("collected start points: %+v\n", simultaneousPaths) log.Printf("collected start points: %+v\n", simultaneousPaths)
return simultaneousPaths
}
// concurrent iteraction type GhostPathInfo struct {
for !isGhostWayDone(simultaneousPaths) { 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() direction := path.next()
for i, curNode := range simultaneousPaths { runnerNode = getNextNode(net, runnerNode, direction)
simultaneousPaths[i] = getNextNode(net, curNode, direction) initialSteps += 1
} }
// log.Printf("done step into %+v\n", simultaneousPaths) // one more step for starting to check for cycle
stepsNum += 1 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 stepsNum return GhostPathInfo{
InitialSteps: initialSteps,
CycleLen: cycleLen,
}
} }
func isGhostWayDone(simulaneousPath []Node) bool { func GhostTraverse(net Network, path Path) int {
containsNonZEnding := slices.ContainsFunc(simulaneousPath, func(curNode Node) bool { simultaneousPaths := getGhostStartNodes(net)
name := curNode.Name pathInfos := make([]GhostPathInfo, 0, len(simultaneousPaths))
last := name[len(name) - 1] for _, pathStart := range simultaneousPaths {
return last != 'Z' pathInfos = append(pathInfos, getGhostPathInfo(pathStart, net, path.Instruction))
}) }
// log.Printf("checking if done for %+v : %t", simulaneousPath, !containsNonZEnding) log.Printf("path infos are %+v\n", pathInfos)
return !containsNonZEnding
// 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 { func getNextNode(net Network, curNode Node, direction rune) Node {

29
day8/notes.org Normal file
View File

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