AdventOfCode2021/12/main.go
2021-12-12 13:03:33 -05:00

151 lines
3.1 KiB
Go

package main
import (
"bufio"
"fmt"
"os"
"strings"
"sync"
"time"
)
func main() {
start := time.Now()
partOne()
duration := time.Since(start)
partTwo()
duration2 := time.Since(start)
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
}
func makeScanner(test bool) *bufio.Scanner {
var f *os.File
if test {
f, _ = os.Open("inputs/testinput")
} else {
f, _ = os.Open("inputs/input")
}
reader := bufio.NewReader(f)
return bufio.NewScanner(reader)
}
type room struct {
name string
links []string
}
func isBigRoom(name string) bool {
return strings.ToUpper(name) == name
}
func canVisit(targetRoom room, visitedRooms []string) bool {
if isBigRoom(targetRoom.name) {
return true
}
for _, v := range visitedRooms {
if targetRoom.name == v {
return false
}
}
return true
}
func doubleSmallAlready(visitedRooms []string) bool {
counts := map[string]int{}
for _, v := range visitedRooms {
counts[v]++
}
for room, v := range counts {
if v == 2 && !isBigRoom(room) {
return true
}
}
return false
}
func descend(rooms map[string]room, currentRoom string, path []string, success chan bool, canVisitSmallRoomTwice bool) {
var wg sync.WaitGroup
if currentRoom == "end" {
success <- true
return
}
for _, link := range rooms[currentRoom].links {
newPath := []string{currentRoom}
newPath = append(newPath, path...)
if canVisit(rooms[link], path) || // part one
(canVisitSmallRoomTwice && !doubleSmallAlready(newPath) && link != "start") { // part two
wg.Add(1)
go func(link string, path []string) {
defer wg.Done()
descend(rooms, link, path, success, canVisitSmallRoomTwice)
}(link, newPath)
}
}
wg.Wait()
}
func partOne() {
scanner := makeScanner(false)
rooms := map[string]room{}
for scanner.Scan() {
line := scanner.Text()
p := strings.Split(line, "-")
// create rooms if we haven't seen them before
if _, ok := rooms[p[0]]; !ok {
rooms[p[0]] = room{name: p[0]}
}
if _, ok := rooms[p[1]]; !ok {
rooms[p[1]] = room{name: p[1]}
}
// set up links
a := rooms[p[0]]
b := rooms[p[1]]
a.links = append(a.links, rooms[p[1]].name)
b.links = append(b.links, rooms[p[0]].name)
rooms[p[0]] = a
rooms[p[1]] = b
}
successes := make(chan bool, 10000)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
descend(rooms, "start", []string{}, successes, false)
}()
wg.Wait()
fmt.Printf("%+v\n", len(successes))
}
func partTwo() {
scanner := makeScanner(false)
rooms := map[string]room{}
for scanner.Scan() {
line := scanner.Text()
p := strings.Split(line, "-")
// create rooms if we haven't seen them before
if _, ok := rooms[p[0]]; !ok {
rooms[p[0]] = room{name: p[0]}
}
if _, ok := rooms[p[1]]; !ok {
rooms[p[1]] = room{name: p[1]}
}
// set up links
a := rooms[p[0]]
b := rooms[p[1]]
a.links = append(a.links, rooms[p[1]].name)
b.links = append(b.links, rooms[p[0]].name)
rooms[p[0]] = a
rooms[p[1]] = b
}
successes := make(chan bool, 200000)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
descend(rooms, "start", []string{}, successes, true)
}()
wg.Wait()
fmt.Printf("%+v\n", len(successes))
}