2022 Day 16 Complete

This commit is contained in:
Brian Buller 2022-12-28 13:37:03 -06:00
parent d940cade58
commit 562faef625
3 changed files with 305 additions and 125 deletions

52
2022/day16/input Normal file
View File

@ -0,0 +1,52 @@
Valve AP has flow rate=0; tunnels lead to valves AA, ON
Valve QN has flow rate=21; tunnels lead to valves RI, CG
Valve LK has flow rate=0; tunnels lead to valves XM, AA
Valve HA has flow rate=0; tunnels lead to valves WH, KF
Valve DS has flow rate=16; tunnel leads to valve II
Valve KD has flow rate=0; tunnels lead to valves KG, QB
Valve JW has flow rate=0; tunnels lead to valves AD, KF
Valve HU has flow rate=0; tunnels lead to valves UK, CO
Valve AE has flow rate=10; tunnels lead to valves IR, PT, UV
Valve XA has flow rate=0; tunnels lead to valves CG, EU
Valve SE has flow rate=17; tunnels lead to valves YR, AD
Valve TR has flow rate=0; tunnels lead to valves AL, CS
Valve BS has flow rate=0; tunnels lead to valves YH, XM
Valve IJ has flow rate=24; tunnels lead to valves XN, WE
Valve AA has flow rate=0; tunnels lead to valves LK, AP, IZ, PC, QD
Valve KG has flow rate=0; tunnels lead to valves KD, CS
Valve QV has flow rate=0; tunnels lead to valves XM, II
Valve PC has flow rate=0; tunnels lead to valves AA, YF
Valve GJ has flow rate=20; tunnel leads to valve RI
Valve UV has flow rate=0; tunnels lead to valves UK, AE
Valve IR has flow rate=0; tunnels lead to valves EU, AE
Valve EU has flow rate=13; tunnels lead to valves IR, DT, XA, ON
Valve ED has flow rate=0; tunnels lead to valves XN, CO
Valve DT has flow rate=0; tunnels lead to valves EU, UK
Valve YE has flow rate=0; tunnels lead to valves XM, WS
Valve AD has flow rate=0; tunnels lead to valves JW, SE
Valve WE has flow rate=0; tunnels lead to valves IJ, NA
Valve UK has flow rate=5; tunnels lead to valves UV, DT, QD, HU
Valve YR has flow rate=0; tunnels lead to valves OS, SE
Valve II has flow rate=0; tunnels lead to valves QV, DS
Valve GT has flow rate=0; tunnels lead to valves CS, MN
Valve YH has flow rate=0; tunnels lead to valves BS, QB
Valve BQ has flow rate=0; tunnels lead to valves XM, KF
Valve OS has flow rate=0; tunnels lead to valves YR, NA
Valve WH has flow rate=0; tunnels lead to valves QB, HA
Valve QB has flow rate=4; tunnels lead to valves WH, KD, YH, IZ
Valve ON has flow rate=0; tunnels lead to valves AP, EU
Valve IZ has flow rate=0; tunnels lead to valves AA, QB
Valve MN has flow rate=25; tunnel leads to valve GT
Valve CG has flow rate=0; tunnels lead to valves XA, QN
Valve QD has flow rate=0; tunnels lead to valves UK, AA
Valve AL has flow rate=0; tunnels lead to valves KF, TR
Valve XN has flow rate=0; tunnels lead to valves ED, IJ
Valve WS has flow rate=0; tunnels lead to valves YE, CS
Valve CO has flow rate=18; tunnels lead to valves ED, PT, HU
Valve PT has flow rate=0; tunnels lead to valves CO, AE
Valve RI has flow rate=0; tunnels lead to valves QN, GJ
Valve CS has flow rate=9; tunnels lead to valves YF, GT, WS, TR, KG
Valve YF has flow rate=0; tunnels lead to valves PC, CS
Valve NA has flow rate=23; tunnels lead to valves OS, WE
Valve KF has flow rate=12; tunnels lead to valves HA, AL, JW, BQ
Valve XM has flow rate=3; tunnels lead to valves LK, QV, YE, BS, BQ

View File

@ -2,111 +2,184 @@ package main
import ( import (
"fmt" "fmt"
"math" "regexp"
"strconv"
"strings" "strings"
h "git.bullercodeworks.com/brian/adventofcode/helpers" h "git.bullercodeworks.com/brian/adventofcode/helpers"
) )
var valveregexp = regexp.MustCompile(`([A-Z]{2}).*=(\d+);.*?((?:[A-Z]{2}(?:, )?)+)`)
func main() { func main() {
inp := h.StdinToStringSlice() rooms := parseRooms(h.StdinToStringSlice())
part1(inp) graph := floydWarshall(rooms)
v := NewVolcano(rooms, graph)
r := part1(v)
v = NewVolcano(rooms, graph)
part2(v, r)
} }
func part1(inp []string) { func part1(v *Volcano) uint16 {
volcano := NewVolcano(inp) var dfs func(target, pressure, minute, on, node uint16) uint16
timeLeft := 30 dfs = func(target, pressure, minute, on, node uint16) uint16 {
currRoom := volcano.FindRoom("AA") max := pressure
_, _ = timeLeft, currRoom for _, w := range v.goodbits {
fmt.Println("Steps from AA -> JJ:", volcano.CountSteps("AA", "JJ")) if node == w[0] || w[0] == v.start || w[0]&on != 0 {
continue
}
l := v.bitgraphs[node|w[0]] + 1
if minute+l > target {
continue
}
if next := dfs(target, pressure+(target-minute-l)*w[1], minute+l, on|w[0], w[0]); next > max {
max = next
}
}
return max
}
res := dfs(30, 0, 0, 0, v.start)
fmt.Println("# Part 1")
fmt.Println(res)
return res
}
func part2(v *Volcano, p1 uint16) {
var dfspaths func(target, pressure, minute, on, node, path uint16) [][2]uint16
dfspaths = func(target, pressure, minute, on, node, path uint16) [][2]uint16 {
paths := [][2]uint16{{pressure, path}}
for _, w := range v.goodbits {
if w[0] == node || w[0] == v.start || w[0]&on != 0 {
continue
}
l := v.bitgraphs[node|w[0]] + 1
if minute+l > target {
continue
}
paths = append(paths, dfspaths(target, pressure+(target-minute-l)*w[1], minute+l, on|w[0], w[0], path|w[0])...)
}
return paths
}
allpaths := dfspaths(26, 0, 0, 0, v.start, 0)
// reduce paths (presumably, both paths are at least half of part 1)
var trimpaths [][2]uint16
for _, p := range allpaths {
if p[0] > p1/2 {
trimpaths = append(trimpaths, p)
}
}
// compare all paths to find max
var max uint16 = 0
for idx := 0; idx < len(trimpaths); idx += 1 {
for jdx := idx + 1; jdx < len(trimpaths); jdx += 1 {
if trimpaths[idx][1]&trimpaths[jdx][1] != 0 {
continue
}
if m := trimpaths[idx][0] + trimpaths[jdx][0]; m > max {
max = m
}
}
}
fmt.Println("# Part 2")
fmt.Println(max)
} }
type Volcano struct { type Volcano struct {
rooms []*Room start uint16
goodrooms []*Room
goodbits [][2]uint16
bitfield map[*Room]uint16
bitgraphs []uint16
} }
func NewVolcano(inp []string) *Volcano { func NewVolcano(rooms []*Room, graph map[*Room]map[*Room]uint16) *Volcano {
v := &Volcano{} v := Volcano{}
for i := range inp {
v.rooms = append(v.rooms, StringToRoom(inp[i])) // pick valves with flow and starting point
} for _, r := range rooms {
for i := range v.rooms { if r.Rate > 0 || r.Name == "AA" {
for _, valve := range v.rooms[i].RawTunnels { v.goodrooms = append(v.goodrooms, r)
v.rooms[i].Tunnels = append(v.rooms[i].Tunnels, v.FindRoom(valve))
} }
} }
return v
}
func (v *Volcano) CountSteps(from string, to string) int { // assign bits
start, end := v.FindRoom(from), v.FindRoom(to) v.bitfield = make(map[*Room]uint16)
if start == nil || end == nil { for idx, r := range v.goodrooms {
fmt.Println("Couldn't find requested rooms:", from, ":", start, " ; ", to, ":", end) v.bitfield[r] = 1 << idx
return math.MaxInt
} }
return v.TrackStepCount(start, end, []*Room{})
}
func (v *Volcano) TrackStepCount(from *Room, to *Room, visited []*Room) int { // find start
if from == to { for _, r := range v.goodrooms {
return 0 if r.Name == "AA" {
} v.start = v.bitfield[r]
minSteps := math.MaxInt break
for _, t := range from.Tunnels {
fmt.Println("TrackStepCount:", from, "->", to, "::", t)
if !IsRoomIn(t, visited) {
fmt.Println(" Haven't Visited")
wrk := v.TrackStepCount(t, to, append(visited, t)) + 1
fmt.Println(" From", from, "to", to, "in", wrk)
minSteps = h.Min(minSteps, wrk)
} }
} }
return minSteps
}
func (v *Volcano) FindRoom(valve string) *Room { // create slice for fast edge lookup
for _, r := range v.rooms { v.bitgraphs = make([]uint16, 0xffff)
if r.Valve == valve { for _, v1 := range v.goodrooms {
return r for _, v2 := range v.goodrooms {
v.bitgraphs[v.bitfield[v1]|v.bitfield[v2]] = graph[v1][v2]
} }
} }
return nil
}
func IsRoomIn(room *Room, rooms []*Room) bool { // create slice for fast node lookup
for i := range rooms { v.goodbits = make([][2]uint16, len(v.goodrooms))
if rooms[i] == room { for idx, r := range v.goodrooms {
return true v.goodbits[idx] = [2]uint16{v.bitfield[r], r.Rate}
}
} }
return false return &v
} }
type Room struct { type Room struct {
Valve string Name string
FlowRate int Rate uint16
RawTunnels []string Edges string
Tunnels []*Room
} }
func StringToRoom(s string) *Room { func parseRooms(inp []string) []*Room {
room := &Room{} rooms := make([]*Room, len(inp))
r := strings.NewReader(s) for idx, line := range inp {
fmt.Fscanf(r, "Valve %s has flow rate=%d; tunnels lead to valve", &room.Valve, &room.FlowRate) m := valveregexp.FindStringSubmatch(line)
readTunnels := strings.Split(s, " valve")[1] i, _ := strconv.Atoi(m[2])
if readTunnels[0] == ' ' { rooms[idx] = &Room{Name: m[1], Rate: uint16(i), Edges: m[3]}
readTunnels = readTunnels[1:]
} else {
readTunnels = readTunnels[2:]
} }
room.RawTunnels = strings.Split(readTunnels, ", ") return rooms
return room
} }
func (r Room) String() string { func floydWarshall(valves []*Room) map[*Room]map[*Room]uint16 {
return r.Valve graph := make(map[*Room]map[*Room]uint16)
} for _, v1 := range valves {
graph[v1] = make(map[*Room]uint16)
for _, v2 := range valves {
if v1 == v2 {
graph[v1][v2] = 0
} else if strings.Contains(v1.Edges, v2.Name) {
graph[v1][v2] = 1
} else {
graph[v1][v2] = 0xff
}
}
}
func (r Room) FullString() string { for _, k := range valves {
return fmt.Sprintf("Valve %s has flow rate=%d; tunnels lead to valves %v", r.Valve, r.FlowRate, r.RawTunnels) for _, i := range valves {
for _, j := range valves {
if graph[i][j] > graph[i][k]+graph[k][j] {
graph[i][j] = graph[i][k] + graph[k][j]
}
}
}
}
return graph
} }

View File

@ -1,46 +1,24 @@
Advent of Code Advent of Code
br0xen (AoC++) 47*
• [About]
• [Events]
• [Shop]
• [Settings]
• [Log Out]
br0xen (AoC++) 29*
      /^2022$/
• [Calendar]
• [AoC++]
• [Sponsors]
• [Leaderboard]
• [Stats]
Our sponsors help make Advent of Code possible:
Sentry.io - More than 3.5 million developers across 85,000 organizations ship better software, faster, with Sentry. What
are you waiting for?
--- Day 16: Proboscidea Volcanium --- --- Day 16: Proboscidea Volcanium ---
The sensors have led you to the origin of the distress signal: yet another handheld device, just like the one the Elves The sensors have led you to the origin of the distress signal: yet another handheld device, just like the one the Elves gave you. However, you don't see
gave you. However, you don't see any Elves around; instead, the device is surrounded by elephants! They must have gotten any Elves around; instead, the device is surrounded by elephants! They must have gotten lost in these tunnels, and one of the elephants apparently
lost in these tunnels, and one of the elephants apparently figured out how to turn on the distress signal. figured out how to turn on the distress signal.
The ground rumbles again, much stronger this time. What kind of cave is this, exactly? You scan the cave with your The ground rumbles again, much stronger this time. What kind of cave is this, exactly? You scan the cave with your handheld device; it reports mostly
handheld device; it reports mostly igneous rock, some ash, pockets of pressurized gas, magma... this isn't just a cave, igneous rock, some ash, pockets of pressurized gas, magma... this isn't just a cave, it's a volcano!
it's a volcano!
You need to get the elephants out of here, quickly. Your device estimates that you have 30 minutes before the volcano You need to get the elephants out of here, quickly. Your device estimates that you have 30 minutes before the volcano erupts, so you don't have time to
erupts, so you don't have time to go back out the way you came in. go back out the way you came in.
You scan the cave for other options and discover a network of pipes and pressure-release valves. You aren't sure how You scan the cave for other options and discover a network of pipes and pressure-release valves. You aren't sure how such a system got into a volcano,
such a system got into a volcano, but you don't have time to complain; your device produces a report (your puzzle input) but you don't have time to complain; your device produces a report (your puzzle input) of each valve's flow rate if it were opened (in pressure per
of each valve's flow rate if it were opened (in pressure per minute) and the tunnels you could use to move between the minute) and the tunnels you could use to move between the valves.
valves.
There's even a valve in the room you and the elephants are currently standing in labeled AA. You estimate it will take There's even a valve in the room you and the elephants are currently standing in labeled AA. You estimate it will take you one minute to open a single
you one minute to open a single valve and one minute to follow any tunnel from one valve to another. What is the most valve and one minute to follow any tunnel from one valve to another. What is the most pressure you could release?
pressure you could release?
For example, suppose you had the following scan output: For example, suppose you had the following scan output:
@ -55,16 +33,14 @@
Valve II has flow rate=0; tunnels lead to valves AA, JJ Valve II has flow rate=0; tunnels lead to valves AA, JJ
Valve JJ has flow rate=21; tunnel leads to valve II Valve JJ has flow rate=21; tunnel leads to valve II
All of the valves begin closed. You start at valve AA, but it must be damaged or jammed or something: its flow rate is All of the valves begin closed. You start at valve AA, but it must be damaged or jammed or something: its flow rate is 0, so there's no point in opening
0, so there's no point in opening it. However, you could spend one minute moving to valve BB and another minute opening it. However, you could spend one minute moving to valve BB and another minute opening it; doing so would release pressure during the remaining 28
it; doing so would release pressure during the remaining 28 minutes at a flow rate of 13, a total eventual pressure minutes at a flow rate of 13, a total eventual pressure release of 28 * 13 = 364. Then, you could spend your third minute moving to valve CC and your
release of 28 * 13 = 364. Then, you could spend your third minute moving to valve CC and your fourth minute opening it, fourth minute opening it, providing an additional 26 minutes of eventual pressure release at a flow rate of 2, or 52 total pressure released by valve
providing an additional 26 minutes of eventual pressure release at a flow rate of 2, or 52 total pressure released by CC.
valve CC.
Making your way through the tunnels like this, you could probably open many or all of the valves by the time 30 minutes Making your way through the tunnels like this, you could probably open many or all of the valves by the time 30 minutes have elapsed. However, you need
have elapsed. However, you need to release as much pressure as possible, so you'll need to be methodical. Instead, to release as much pressure as possible, so you'll need to be methodical. Instead, consider this approach:
consider this approach:
== Minute 1 == == Minute 1 ==
No valves are open. No valves are open.
@ -184,11 +160,93 @@
Work out the steps to release the most pressure in 30 minutes. What is the most pressure you can release? Work out the steps to release the most pressure in 30 minutes. What is the most pressure you can release?
To begin, get your puzzle input. Your puzzle answer was 1862.
Answer: _____________________ [ [Submit] ] --- Part Two ---
You can also [Shareon Twitter Mastodon] this puzzle. You're worried that even with an optimal approach, the pressure released won't be enough. What if you got one of the elephants to help you?
It would take you 4 minutes to teach an elephant how to open the right valves in the right order, leaving you with only 26 minutes to actually execute
your plan. Would having two of you working together be better, even if it means having less time? (Assume that you teach the elephant before opening any
valves yourself, giving you both the same full 26 minutes.)
In the example above, you could teach the elephant to help you as follows:
== Minute 1 ==
No valves are open.
You move to valve II.
The elephant moves to valve DD.
== Minute 2 ==
No valves are open.
You move to valve JJ.
The elephant opens valve DD.
== Minute 3 ==
Valve DD is open, releasing 20 pressure.
You open valve JJ.
The elephant moves to valve EE.
== Minute 4 ==
Valves DD and JJ are open, releasing 41 pressure.
You move to valve II.
The elephant moves to valve FF.
== Minute 5 ==
Valves DD and JJ are open, releasing 41 pressure.
You move to valve AA.
The elephant moves to valve GG.
== Minute 6 ==
Valves DD and JJ are open, releasing 41 pressure.
You move to valve BB.
The elephant moves to valve HH.
== Minute 7 ==
Valves DD and JJ are open, releasing 41 pressure.
You open valve BB.
The elephant opens valve HH.
== Minute 8 ==
Valves BB, DD, HH, and JJ are open, releasing 76 pressure.
You move to valve CC.
The elephant moves to valve GG.
== Minute 9 ==
Valves BB, DD, HH, and JJ are open, releasing 76 pressure.
You open valve CC.
The elephant moves to valve FF.
== Minute 10 ==
Valves BB, CC, DD, HH, and JJ are open, releasing 78 pressure.
The elephant moves to valve EE.
== Minute 11 ==
Valves BB, CC, DD, HH, and JJ are open, releasing 78 pressure.
The elephant opens valve EE.
(At this point, all valves are open.)
== Minute 12 ==
Valves BB, CC, DD, EE, HH, and JJ are open, releasing 81 pressure.
...
== Minute 20 ==
Valves BB, CC, DD, EE, HH, and JJ are open, releasing 81 pressure.
...
== Minute 26 ==
Valves BB, CC, DD, EE, HH, and JJ are open, releasing 81 pressure.
With the elephant helping, after 26 minutes, the best you could do would release a total of 1707 pressure.
With you and an elephant working together for 26 minutes, what is the most pressure you could release?
Your puzzle answer was 2422.
Both parts of this puzzle are complete! They provide two gold stars: **
References References
@ -196,7 +254,6 @@ References
. https://adventofcode.com/ . https://adventofcode.com/
. https://adventofcode.com/2022/about . https://adventofcode.com/2022/about
. https://adventofcode.com/2022/events . https://adventofcode.com/2022/events
. https://teespring.com/stores/advent-of-code
. https://adventofcode.com/2022/settings . https://adventofcode.com/2022/settings
. https://adventofcode.com/2022/auth/logout . https://adventofcode.com/2022/auth/logout
. Advent of Code Supporter . Advent of Code Supporter
@ -208,7 +265,5 @@ References
. https://adventofcode.com/2022/leaderboard . https://adventofcode.com/2022/leaderboard
. https://adventofcode.com/2022/stats . https://adventofcode.com/2022/stats
. https://adventofcode.com/2022/sponsors . https://adventofcode.com/2022/sponsors
. https://sentry.io/ . https://adventofcode.com/2022
. https://adventofcode.com/2022/day/16/input . https://adventofcode.com/2022/day/16/input
. https://twitter.com/intent/tweet?text=%22Proboscidea+Volcanium%22+%2D+Day+16+%2D+Advent+of+Code+2022&url=https%3A%2F%2Fadventofcode%2Ecom%2F2022%2Fday%2F16&related=ericwastl&hashtags=AdventOfCode
. javascript:void(0);