-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathchallenge.go
More file actions
123 lines (99 loc) · 2.19 KB
/
challenge.go
File metadata and controls
123 lines (99 loc) · 2.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package challenge
import (
"strings"
"github.com/codemicro/adventOfCode/lib/aocgo"
)
type node struct {
isSmall bool
name string
}
func newNode(x string) *node {
return &node{
isSmall: x == strings.ToLower(x),
name: x,
}
}
type graph struct {
nodes map[string]*node
edges map[*node][]*node
}
func newGraph() *graph {
return &graph{
nodes: make(map[string]*node),
edges: make(map[*node][]*node),
}
}
func parse(instr string) *graph {
g := newGraph()
for _, line := range strings.Split(strings.TrimSpace(instr), "\n") {
sp := strings.Split(line, "-")
from := sp[0]
to := sp[1]
fromNode := g.nodes[from]
toNode := g.nodes[to]
if fromNode == nil {
fromNode = newNode(from)
g.nodes[from] = fromNode
}
if toNode == nil {
toNode = newNode(to)
g.nodes[to] = toNode
}
g.edges[fromNode] = append(g.edges[fromNode], toNode)
g.edges[toNode] = append(g.edges[toNode], fromNode)
}
return g
}
func countRoutesA(cave *graph, fromNode *node, visited *aocgo.Set) int {
if fromNode.name == "end" {
return 1
}
var total int
for _, nextNode := range cave.edges[fromNode] {
if visited.Contains(nextNode) || nextNode.name == "start" {
continue
}
s := visited.ShallowCopy()
if fromNode.isSmall {
s.Add(fromNode)
}
total += countRoutesA(cave, nextNode, s)
}
return total
}
func countRoutesB(cave *graph, fromNode *node, visited *aocgo.Set, extraUsed bool) int {
if fromNode.name == "end" {
return 1
}
var total int
for _, nextNode := range cave.edges[fromNode] {
if nextNode.name == "start" {
continue
}
var y bool
if x := visited.Contains(nextNode); x && extraUsed {
continue
} else if x {
y = true
} else {
y = extraUsed
}
s := visited.ShallowCopy()
if fromNode.isSmall {
s.Add(fromNode)
}
total += countRoutesB(cave, nextNode, s, y)
}
return total
}
type Challenge struct {
aocgo.BaseChallenge
}
func (c Challenge) One(instr string) (interface{}, error) {
cave := parse(instr)
return countRoutesA(cave, cave.nodes["start"], aocgo.NewSet()), nil
}
func (c Challenge) Two(instr string) (interface{}, error) {
cave := parse(instr)
return countRoutesB(cave, cave.nodes["start"], aocgo.NewSet(), false), nil
}