diff --git a/2021/day12/input b/2021/day12/input new file mode 100644 index 0000000..756681b --- /dev/null +++ b/2021/day12/input @@ -0,0 +1,23 @@ +pn-TY +rp-ka +az-aw +al-IV +pn-co +end-rp +aw-TY +rp-pn +al-rp +end-al +IV-co +end-TM +co-TY +TY-ka +aw-pn +aw-IV +pn-IV +IV-ka +TM-rp +aw-PD +start-IV +start-co +start-pn diff --git a/2021/day12/main.go b/2021/day12/main.go new file mode 100644 index 0000000..6f4becf --- /dev/null +++ b/2021/day12/main.go @@ -0,0 +1,158 @@ +package main + +import ( + "fmt" + "strings" + + h "git.bullercodeworks.com/brian/adventofcode/helpers" +) + +func main() { + inp := h.StdinToStringSlice() + part1(BuildCaves(inp)) + fmt.Println() + part2(BuildCaves(inp)) +} + +func BuildCaves(inp []string) map[string]Cave { + ret := make(map[string]Cave) + for i := range inp { + pts := strings.Split(inp[i], "-") + var c1, c2 Cave + var ok bool + if c1, ok = ret[pts[0]]; !ok { + c1 = NewCave(pts[0]) + } + if c2, ok = ret[pts[1]]; !ok { + c2 = NewCave(pts[1]) + } + if !c1.ExitsTo(c2) { + c1.Exits = append(c1.Exits, c2.Name) + } + if !c2.ExitsTo(c1) { + c2.Exits = append(c2.Exits, c1.Name) + } + ret[c1.Name] = c1 + ret[c2.Name] = c2 + } + return ret +} + +func part1(inp map[string]Cave) { + curr, _ := inp["start"] + res := part1_findPaths([]Cave{curr}, inp) + fmt.Println("# Part 1") + fmt.Println("There are", len(res), "paths") +} + +func part1_shouldVisit(c string, path []Cave) bool { + if c[0] < 'A' || c[0] > 'Z' { + for i := range path { + if path[i].Name == c { + return false + } + } + } + return true +} + +func part1_findPaths(path []Cave, system map[string]Cave) [][]Cave { + var ret [][]Cave + curr := path[len(path)-1] + if curr.Name == "end" { + return append(ret, path) + } + for _, c := range curr.Exits { + if part1_shouldVisit(c, path) { + newPaths := part1_findPaths(append(path, system[c]), system) + ret = append(ret, newPaths...) + } + } + return ret +} + +func part2(inp map[string]Cave) { + curr, _ := inp["start"] + res := part2_findPaths([]Cave{curr}, inp) + fmt.Println("# Part 2") + fmt.Println("There are", len(res), "paths") +} + +func part2_shouldVisit(c string, path []Cave) bool { + if path[len(path)-1].Name == "end" { + // If the previous spot was end, we shouldn't visit anything + return false + } + if c[0] < 'A' || c[0] > 'Z' { + if c == "start" { // We never return to start + return false + } + // Check if we've already visited this cave + visits := make(map[string]int) + var visited, twice bool + for i := range path { + if path[i].Name == c { + visited = true + } + visits[path[i].Name]++ + if !path[i].Big && visits[path[i].Name] > 1 { + twice = true + } + } + if visited && twice { + return false + } + } + return true +} + +func part2_findPaths(path []Cave, system map[string]Cave) [][]Cave { + var ret [][]Cave + curr := path[len(path)-1] + if curr.Name == "end" { + return append(ret, path) + } + for _, c := range curr.Exits { + if part2_shouldVisit(c, path) { + newPaths := part2_findPaths(append(path, system[c]), system) + ret = append(ret, newPaths...) + } + } + return ret +} + +type Cave struct { + Name string + Big bool + Exits []string +} + +func NewCave(n string) Cave { + return Cave{ + Name: n, + Big: (n[0] >= 'A' && n[0] <= 'Z'), + } +} + +func (c Cave) ExitsTo(e Cave) bool { + for i := range c.Exits { + if c.Exits[i] == e.Name { + return true + } + } + return false +} + +func (c Cave) String() string { + return c.Name +} + +func (c Cave) Detail() string { + return fmt.Sprintf("{%s -> %s}", c.Name, c.Exits) +} + +func PrintMap(inp map[string]Cave) { + for k := range inp { + fmt.Println(inp[k].Detail()) + } +} diff --git a/2021/day12/problem b/2021/day12/problem new file mode 100644 index 0000000..88e911d --- /dev/null +++ b/2021/day12/problem @@ -0,0 +1,189 @@ +# Advent of Code + +--- Day 12: Passage Pathing --- + + With your submarine's subterranean subsystems subsisting suboptimally, the only way you're getting out of this cave anytime soon is by finding a + path yourself. Not just a path - the only way to know if you've found the best path is to find all of them. + + Fortunately, the sensors are still mostly working, and so you build a rough map of the remaining caves (your puzzle input). For example: + + start-A + start-b + A-c + A-b + b-d + A-end + b-end + + This is a list of how all of the caves are connected. You start in the cave named start, and your destination is the cave named end. An entry + like b-d means that cave b is connected to cave d - that is, you can move between them. + + So, the above cave system looks roughly like this: + + start + / \ + c--A-----b--d + \ / + end + + Your goal is to find the number of distinct paths that start at start, end at end, and don't visit small caves more than once. There are two + types of caves: big caves (written in uppercase, like A) and small caves (written in lowercase, like b). It would be a waste of time to visit any + small cave more than once, but big caves are large enough that it might be worth visiting them multiple times. So, all paths you find should + visit small caves at most once, and can visit big caves any number of times. + + Given these rules, there are 10 paths through this example cave system: + + start,A,b,A,c,A,end + start,A,b,A,end + start,A,b,end + start,A,c,A,b,A,end + start,A,c,A,b,end + start,A,c,A,end + start,A,end + start,b,A,c,A,end + start,b,A,end + start,b,end + + (Each line in the above list corresponds to a single path; the caves visited by that path are listed in the order they are visited and separated + by commas.) + + Note that in this cave system, cave d is never visited by any path: to do so, cave b would need to be visited twice (once on the way to cave d + and a second time when returning from cave d), and since cave b is small, this is not allowed. + + Here is a slightly larger example: + + dc-end + HN-start + start-kj + dc-start + dc-HN + LN-dc + HN-end + kj-sa + kj-HN + kj-dc + + The 19 paths through it are as follows: + + start,HN,dc,HN,end + start,HN,dc,HN,kj,HN,end + start,HN,dc,end + start,HN,dc,kj,HN,end + start,HN,end + start,HN,kj,HN,dc,HN,end + start,HN,kj,HN,dc,end + start,HN,kj,HN,end + start,HN,kj,dc,HN,end + start,HN,kj,dc,end + start,dc,HN,end + start,dc,HN,kj,HN,end + start,dc,end + start,dc,kj,HN,end + start,kj,HN,dc,HN,end + start,kj,HN,dc,end + start,kj,HN,end + start,kj,dc,HN,end + start,kj,dc,end + + Finally, this even larger example has 226 paths through it: + + fs-end + he-DX + fs-he + start-DX + pj-DX + end-zg + zg-sl + zg-pj + pj-he + RW-he + fs-DX + pj-RW + zg-RW + start-pj + he-WI + zg-he + pj-fs + start-RW + + How many paths through this cave system are there that visit small caves at most once? + + Your puzzle answer was 4413. + +--- Part Two --- + + After reviewing the available paths, you realize you might have time to visit a single small cave twice. Specifically, big caves can be visited + any number of times, a single small cave can be visited at most twice, and the remaining small caves can be visited at most once. However, the + caves named start and end can only be visited exactly once each: once you leave the start cave, you may not return to it, and once you reach the + end cave, the path must end immediately. + + Now, the 36 possible paths through the first example above are: + + start,A,b,A,b,A,c,A,end + start,A,b,A,b,A,end + start,A,b,A,b,end + start,A,b,A,c,A,b,A,end + start,A,b,A,c,A,b,end + start,A,b,A,c,A,c,A,end + start,A,b,A,c,A,end + start,A,b,A,end + start,A,b,d,b,A,c,A,end + start,A,b,d,b,A,end + start,A,b,d,b,end + start,A,b,end + start,A,c,A,b,A,b,A,end + start,A,c,A,b,A,b,end + start,A,c,A,b,A,c,A,end + start,A,c,A,b,A,end + start,A,c,A,b,d,b,A,end + start,A,c,A,b,d,b,end + start,A,c,A,b,end + start,A,c,A,c,A,b,A,end + start,A,c,A,c,A,b,end + start,A,c,A,c,A,end + start,A,c,A,end + start,A,end + start,b,A,b,A,c,A,end + start,b,A,b,A,end + start,b,A,b,end + start,b,A,c,A,b,A,end + start,b,A,c,A,b,end + start,b,A,c,A,c,A,end + start,b,A,c,A,end + start,b,A,end + start,b,d,b,A,c,A,end + start,b,d,b,A,end + start,b,d,b,end + start,b,end + + The slightly larger example above now has 103 paths through it, and the even larger example now has 3509 paths through it. + + Given these new rules, how many paths through this cave system are there? + + Your puzzle answer was 118803. + + Both parts of this puzzle are complete! They provide two gold stars: ** + + At this point, you should return to your Advent calendar and try another puzzle. + + If you still want to see it, you can get your puzzle input. + +References + + Visible links + . https://adventofcode.com/ + . https://adventofcode.com/2021/about + . https://adventofcode.com/2021/events + . https://adventofcode.com/2021/settings + . https://adventofcode.com/2021/auth/logout + . Advent of Code Supporter + https://adventofcode.com/2021/support + . https://adventofcode.com/2021 + . https://adventofcode.com/2021 + . https://adventofcode.com/2021/support + . https://adventofcode.com/2021/sponsors + . https://adventofcode.com/2021/leaderboard + . https://adventofcode.com/2021/stats + . https://adventofcode.com/2021/sponsors + . https://adventofcode.com/2021 + . https://adventofcode.com/2021/day/12/input diff --git a/2021/day12/testinput b/2021/day12/testinput new file mode 100644 index 0000000..6fd8c41 --- /dev/null +++ b/2021/day12/testinput @@ -0,0 +1,7 @@ +start-A +start-b +A-c +A-b +b-d +A-end +b-end diff --git a/2021/day12/testinput2 b/2021/day12/testinput2 new file mode 100644 index 0000000..62cc714 --- /dev/null +++ b/2021/day12/testinput2 @@ -0,0 +1,10 @@ +dc-end +HN-start +start-kj +dc-start +dc-HN +LN-dc +HN-end +kj-sa +kj-HN +kj-dc diff --git a/2021/day12/testinput3 b/2021/day12/testinput3 new file mode 100644 index 0000000..65f3833 --- /dev/null +++ b/2021/day12/testinput3 @@ -0,0 +1,18 @@ +fs-end +he-DX +fs-he +start-DX +pj-DX +end-zg +zg-sl +zg-pj +pj-he +RW-he +fs-DX +pj-RW +zg-RW +start-pj +he-WI +zg-he +pj-fs +start-RW