Advertisement
nohar

AoC 2021 Day 12 in Go

Dec 12th, 2021
1,531
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. package main
  2.  
  3. import (
  4.     "aoc/utils"
  5.     "fmt"
  6.     "strings"
  7. )
  8.  
  9. func main() {
  10.     g := NewGraph(utils.ReadLines())
  11.     fmt.Println("part1: ", g.Part1())
  12.     fmt.Println("part2: ", g.Part2())
  13. }
  14.  
  15. type Graph struct {
  16.     edges    [][]uint16
  17.     bigCaves uint16
  18. }
  19.  
  20. func (g *Graph) Part1() int {
  21.     initCache()
  22.     return g.countPathsPart1(startCave, 0)
  23. }
  24.  
  25. func (g *Graph) Part2() int {
  26.     initCache()
  27.     return g.countPathsPart2(startCave, 0)
  28. }
  29.  
  30. const (
  31.     startCave = 1
  32.     endCave   = 0
  33. )
  34.  
  35. func caveMask(cave uint16) uint16 {
  36.     return 1 << cave
  37. }
  38.  
  39. func (g *Graph) countPathsPart1(from uint16, visited uint16) int {
  40.     var count int
  41.     if count, ok := getCachedResult(from, visited); ok {
  42.         return count
  43.     }
  44.     for _, to := range g.edges[from] {
  45.         if to == endCave {
  46.             count++
  47.             continue
  48.         }
  49.         toMask := caveMask(to) &^ g.bigCaves
  50.         if visited&toMask == 0 {
  51.             count += g.countPathsPart1(to, visited|toMask)
  52.         }
  53.     }
  54.     putToCache(from, visited, count)
  55.     return count
  56. }
  57.  
  58. const doubleMask = 1 << 15
  59.  
  60. func (g *Graph) countPathsPart2(from uint16, visited uint16) int {
  61.     var count int
  62.     if count, ok := getCachedResult(from, visited); ok {
  63.         return count
  64.     }
  65.     for _, to := range g.edges[from] {
  66.         if to == endCave {
  67.             count++
  68.             continue
  69.         }
  70.         toMask := caveMask(to) &^ g.bigCaves
  71.         if visited&toMask == 0 {
  72.             count += g.countPathsPart2(to, visited|toMask)
  73.         } else if visited&doubleMask == 0 {
  74.             count += g.countPathsPart2(to, visited|doubleMask)
  75.         }
  76.     }
  77.     putToCache(from, visited, count)
  78.     return count
  79. }
  80.  
  81. // Memoïzation
  82.  
  83. type key struct {
  84.     cave    uint16
  85.     visited uint16
  86. }
  87.  
  88. type cache map[key]int
  89.  
  90. var memo cache
  91.  
  92. func initCache() {
  93.     memo = make(cache, 500)
  94. }
  95.  
  96. func getCachedResult(from uint16, visited uint16) (int, bool) {
  97.     count, ok := memo[key{from, visited}]
  98.     return count, ok
  99. }
  100.  
  101. func putToCache(from uint16, visited uint16, count int) {
  102.     memo[key{from, visited}] = count
  103. }
  104.  
  105. // Input parsing
  106.  
  107. func NewGraph(input []string) *Graph {
  108.     g := newBuilder()
  109.     g.parse(input)
  110.     return &g.Graph
  111. }
  112.  
  113. func newBuilder() *graphBuilder {
  114.     return &graphBuilder{
  115.         Graph: Graph{edges: make([][]uint16, 2, 16)},
  116.         caves: map[string]uint16{
  117.             "start": startCave,
  118.             "end":   endCave,
  119.         },
  120.     }
  121. }
  122.  
  123. type graphBuilder struct {
  124.     Graph
  125.     caves map[string]uint16
  126. }
  127.  
  128. func (g *graphBuilder) parse(input []string) {
  129.     for _, line := range input {
  130.         edge := strings.Split(line, "-")
  131.         c1 := g.getCave(edge[0])
  132.         c2 := g.getCave(edge[1])
  133.         g.addEdge(c1, c2)
  134.     }
  135. }
  136.  
  137. func (g *graphBuilder) addEdge(c1, c2 uint16) {
  138.     if c1 != endCave && c2 != startCave {
  139.         g.edges[c1] = append(g.edges[c1], c2)
  140.     }
  141.     if c1 != startCave && c2 != endCave {
  142.         g.edges[c2] = append(g.edges[c2], c1)
  143.     }
  144. }
  145.  
  146. func (g *graphBuilder) getCave(name string) uint16 {
  147.     if cave, ok := g.caves[name]; ok {
  148.         return cave
  149.     }
  150.     cave := uint16(len(g.caves))
  151.     g.caves[name] = cave
  152.     if 'A' <= name[0] && name[0] <= 'Z' {
  153.         g.bigCaves |= caveMask(cave)
  154.     }
  155.     g.edges = append(g.edges, nil)
  156.     return cave
  157. }
  158.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement