github.com/agrigoryan/aoc_2023_go@v0.0.0-20231216221323-4ace361ec685/day8/d8p2.go (about)

     1  package day8
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  )
     7  
     8  // greatest common divisor (GCD) via Euclidean algorithm
     9  func gcd(a, b int) int {
    10  	for b != 0 {
    11  		t := b
    12  		b = a % b
    13  		a = t
    14  	}
    15  	return a
    16  }
    17  
    18  // find Least Common Multiple (LCM) via GCD
    19  func lcm(a, b int, integers ...int) int {
    20  	result := a * b / gcd(a, b)
    21  
    22  	for i := 0; i < len(integers); i++ {
    23  		result = lcm(result, integers[i])
    24  	}
    25  
    26  	return result
    27  }
    28  
    29  func d8p2(input string) int {
    30  	lines := strings.Split(input, "\n")
    31  
    32  	directions := []rune(lines[0])
    33  
    34  	nodesByName := map[string]*node{}
    35  
    36  	startNodes := []*node{}
    37  
    38  	for _, line := range lines[2:] {
    39  		name := strings.Split(line, " ")[0]
    40  		left := line[strings.Index(line, "(")+1 : strings.Index(line, ",")]
    41  		right := line[strings.Index(line, ", ")+2 : strings.Index(line, ")")]
    42  		nodesByName[name] = &node{name, left, right, name[len(name)-1] == 'Z'}
    43  		if name[len(name)-1] == 'A' {
    44  			startNodes = append(startNodes, nodesByName[name])
    45  		}
    46  	}
    47  
    48  	cycleLength := func(n *node) int {
    49  		steps := 0
    50  		for {
    51  			direction := directions[steps%len(directions)]
    52  			if n.endingNode {
    53  				break
    54  			}
    55  			if direction == 'R' {
    56  				n = nodesByName[n.right]
    57  			} else {
    58  				n = nodesByName[n.left]
    59  			}
    60  			steps += 1
    61  		}
    62  		return steps
    63  	}
    64  
    65  	cycleLengths := make([]int, len(startNodes))
    66  
    67  	for i, n := range startNodes {
    68  		cycleLengths[i] = cycleLength(n)
    69  	}
    70  
    71  	res := lcm(cycleLengths[0], cycleLengths[1], cycleLengths[2:]...)
    72  	fmt.Println(res)
    73  	return res
    74  }