2021 Day 12
This commit is contained in:
parent
020429ff62
commit
b5538b2540
2 changed files with 183 additions and 0 deletions
|
|
@ -91,3 +91,7 @@ func Ints(text string) (ns []int) {
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ExLines(text string) []string {
|
||||
return strings.Split(strings.TrimSpace(text), "\n")
|
||||
}
|
||||
|
|
|
|||
179
2021/day12/main.go
Normal file
179
2021/day12/main.go
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/jdkaplan/advent-of-code/aoc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
lines := aoc.Input().ReadLines("day12.txt")
|
||||
fmt.Println(part1(lines))
|
||||
fmt.Println(part2(lines))
|
||||
}
|
||||
|
||||
func part1(lines []string) int {
|
||||
g := NewGraph(lines)
|
||||
return g.Paths()
|
||||
}
|
||||
func part2(lines []string) int {
|
||||
g := NewGraph(lines)
|
||||
return g.Paths2()
|
||||
}
|
||||
|
||||
type Graph struct {
|
||||
Edges map[string][]string
|
||||
Big map[string]struct{}
|
||||
Small map[string]struct{}
|
||||
}
|
||||
|
||||
func NewGraph(lines []string) *Graph {
|
||||
g := &Graph{
|
||||
Edges: make(map[string][]string),
|
||||
Big: make(map[string]struct{}),
|
||||
Small: make(map[string]struct{}),
|
||||
}
|
||||
for _, l := range lines {
|
||||
a, b := aoc.Cut(l, "-")
|
||||
g.Edges[a] = append(g.Edges[a], b)
|
||||
g.Edges[b] = append(g.Edges[b], a)
|
||||
if isBig(a) {
|
||||
g.Big[a] = struct{}{}
|
||||
} else {
|
||||
g.Small[a] = struct{}{}
|
||||
}
|
||||
if isBig(b) {
|
||||
g.Big[b] = struct{}{}
|
||||
} else {
|
||||
g.Small[b] = struct{}{}
|
||||
}
|
||||
}
|
||||
return g
|
||||
}
|
||||
|
||||
func (g Graph) Neighbors(name string) []string {
|
||||
return g.Edges[name]
|
||||
}
|
||||
|
||||
type path []string
|
||||
|
||||
func (p path) String() string {
|
||||
return strings.Join(p, ",")
|
||||
}
|
||||
|
||||
func (p path) Contains(name string) bool {
|
||||
for _, n := range p {
|
||||
if n == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p path) Tip() string {
|
||||
return p[len(p)-1]
|
||||
}
|
||||
|
||||
func (p path) Plus(name string) path {
|
||||
// Copy memory to avoid overwriting the last element in the slice.
|
||||
p2 := make(path, len(p))
|
||||
copy(p2, p)
|
||||
return append(p2, name)
|
||||
}
|
||||
|
||||
func (g Graph) Paths() (count int) {
|
||||
queue := []path{{"start"}}
|
||||
for len(queue) > 0 {
|
||||
p := queue[0]
|
||||
queue = queue[1:]
|
||||
tip := p.Tip()
|
||||
for _, n := range g.Neighbors(tip) {
|
||||
ext := p.Plus(n)
|
||||
if n == "end" {
|
||||
count++
|
||||
continue
|
||||
}
|
||||
if !isBig(n) && p.Contains(n) {
|
||||
// Don't include small caves twice
|
||||
continue
|
||||
}
|
||||
queue = append(queue, ext)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func isBig(name string) bool {
|
||||
return strings.ToUpper(name) == name
|
||||
}
|
||||
|
||||
type path2 struct {
|
||||
caves []string
|
||||
doubled bool
|
||||
}
|
||||
|
||||
func (p *path2) Plus(name string) (path2, bool) {
|
||||
var caves []string
|
||||
doubled := p.doubled
|
||||
canDupe := isBig(name)
|
||||
for _, c := range p.caves {
|
||||
caves = append(caves, c)
|
||||
if c != name {
|
||||
// No dupe.
|
||||
continue
|
||||
}
|
||||
if canDupe {
|
||||
continue
|
||||
}
|
||||
// c == name for a small cave
|
||||
if doubled {
|
||||
// Already found a doubled cave, can't include this one.
|
||||
return path2{}, false
|
||||
}
|
||||
// Contains two of c now.
|
||||
doubled = true
|
||||
}
|
||||
return path2{
|
||||
caves: append(caves, name),
|
||||
doubled: doubled,
|
||||
}, true
|
||||
}
|
||||
|
||||
func (p path2) String() string {
|
||||
return strings.Join(p.caves, ",")
|
||||
}
|
||||
|
||||
func (p path2) Tip() string {
|
||||
return p.caves[len(p.caves)-1]
|
||||
}
|
||||
|
||||
func (g Graph) Paths2() (count int) {
|
||||
queue := []path2{
|
||||
{
|
||||
caves: []string{"start"},
|
||||
doubled: false,
|
||||
},
|
||||
}
|
||||
for len(queue) > 0 {
|
||||
p := queue[0]
|
||||
queue = queue[1:]
|
||||
tip := p.Tip()
|
||||
for _, n := range g.Neighbors(tip) {
|
||||
if n == "start" {
|
||||
// No loops!
|
||||
continue
|
||||
}
|
||||
ext, ok := p.Plus(n)
|
||||
if n == "end" {
|
||||
count++
|
||||
continue
|
||||
}
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
queue = append(queue, ext)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
Loading…
Reference in a new issue