diff --git a/.gitignore b/.gitignore index 4b1d5ae..5134f6f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -**/*/EXAMPLE.txt +**/*/EXAMPLE*.txt **/*/INPUT.txt **/*/PROBLEM.md diff --git a/cmd/11/main.go b/cmd/11/main.go index 3abab4c..a54a013 100644 --- a/cmd/11/main.go +++ b/cmd/11/main.go @@ -4,11 +4,15 @@ import ( "strings" "github.com/StevanFreeborn/advent-of-code-2025/internal/file" + "github.com/StevanFreeborn/advent-of-code-2025/internal/queue" "github.com/StevanFreeborn/advent-of-code-2025/internal/stack" ) -const START_NODE = "you" -const END_NODE = "out" +const YOU_NODE = "you" +const OUT_NODE = "out" +const SVR_NODE = "svr" +const DAC_NODE = "dac" +const FFT_NODE = "fft" func SolvePartOne(filePath string) int { adjacencyList := map[string][]string{} @@ -21,13 +25,13 @@ func SolvePartOne(filePath string) int { } stack := stack.New[string]() - stack.Push(START_NODE) + stack.Push(YOU_NODE) pathCount := 0 for stack.IsEmpty() == false { current, _ := stack.Pop() - if current == END_NODE { + if current == OUT_NODE { pathCount++ continue } @@ -41,3 +45,73 @@ func SolvePartOne(filePath string) int { return pathCount } + +func SolvePartTwo(filePath string) int { + adjacencyList := map[string][]string{} + inDegrees := map[string]int{} + allNodes := map[string]bool{} + + for line := range file.ReadLines(filePath) { + parts := strings.Split(line, ": ") + from := parts[0] + toList := strings.Split(parts[1], " ") + + allNodes[from] = true + + _, existingInDegrees := inDegrees[from] + + if existingInDegrees == false { + inDegrees[from] = 0 + } + + for _, to := range toList { + allNodes[to] = true + adjacencyList[from] = append(adjacencyList[from], to) + inDegrees[to]++ + } + } + + queue := queue.New[string]() + + for node := range allNodes { + if inDegrees[node] == 0 { + queue.Enqueue(node) + } + } + + processOrder := []string{} + + for queue.IsEmpty() == false { + current, _ := queue.Dequeue() + processOrder = append(processOrder, current) + + for _, neighbor := range adjacencyList[current] { + inDegrees[neighbor]-- + + if inDegrees[neighbor] == 0 { + queue.Enqueue(neighbor) + } + } + } + + pathA := countPaths(SVR_NODE, FFT_NODE, processOrder, adjacencyList) * countPaths(FFT_NODE, DAC_NODE, processOrder, adjacencyList) * countPaths(DAC_NODE, OUT_NODE, processOrder, adjacencyList) + pathB := countPaths(SVR_NODE, DAC_NODE, processOrder, adjacencyList) * countPaths(DAC_NODE, FFT_NODE, processOrder, adjacencyList) * countPaths(FFT_NODE, OUT_NODE, processOrder, adjacencyList) + return pathA + pathB +} + +func countPaths(start string, end string, processOrder []string, adjacencyList map[string][]string) int { + pathsCount := map[string]int{} + pathsCount[start] = 1 + + for _, item := range processOrder { + if pathsCount[item] == 0 { + continue + } + + for _, n := range adjacencyList[item] { + pathsCount[n] += pathsCount[item] + } + } + + return pathsCount[end] +} diff --git a/cmd/11/main_test.go b/cmd/11/main_test.go index dd5ab04..950f6c1 100644 --- a/cmd/11/main_test.go +++ b/cmd/11/main_test.go @@ -9,10 +9,10 @@ import ( func TestSolvePartOneWithExampleInput(t *testing.T) { expected := 5 - result := solution.SolvePartOne("EXAMPLE.txt") + result := solution.SolvePartOne("EXAMPLE_ONE.txt") if result != expected { - t.Errorf("SolvePartOne(EXAMPLE.txt) = %d; want %d", result, expected) + t.Errorf("SolvePartOne(EXAMPLE_ONE.txt) = %d; want %d", result, expected) } } @@ -25,3 +25,23 @@ func TestSolvePartOneWithInput(t *testing.T) { t.Errorf("SolvePartOne(INPUT.txt) = %d; want %d", result, expected) } } + +func TestSolvePartTwoWithExampleInput(t *testing.T) { + expected := 2 + + result := solution.SolvePartTwo("EXAMPLE_TWO.txt") + + if result != expected { + t.Errorf("SolvePartTwo(EXAMPLE_TWO.txt) = %d; want %d", result, expected) + } +} + +func TestSolvePartTwoWithInput(t *testing.T) { + expected := 393_474_305_030_400 + + result := solution.SolvePartTwo("INPUT.txt") + + if result != expected { + t.Errorf("SolvePartTwo(INPUT.txt) = %d; want %d", result, expected) + } +}