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 (
"fmt"
"math"
"regexp"
"strconv"
"strings"
h "git.bullercodeworks.com/brian/adventofcode/helpers"
)
var valveregexp = regexp.MustCompile(`([A-Z]{2}).*=(\d+);.*?((?:[A-Z]{2}(?:, )?)+)`)
func main() {
inp := h.StdinToStringSlice()
part1(inp)
rooms := parseRooms(h.StdinToStringSlice())
graph := floydWarshall(rooms)
v := NewVolcano(rooms, graph)
r := part1(v)
v = NewVolcano(rooms, graph)
part2(v, r)
}
func part1(inp []string) {
volcano := NewVolcano(inp)
timeLeft := 30
currRoom := volcano.FindRoom("AA")
_, _ = timeLeft, currRoom
fmt.Println("Steps from AA -> JJ:", volcano.CountSteps("AA", "JJ"))
func part1(v *Volcano) uint16 {
var dfs func(target, pressure, minute, on, node uint16) uint16
dfs = func(target, pressure, minute, on, node uint16) uint16 {
max := pressure
for _, w := range v.goodbits {
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 {
rooms []*Room
start uint16
goodrooms []*Room
goodbits [][2]uint16
bitfield map[*Room]uint16
bitgraphs []uint16
}
func NewVolcano(inp []string) *Volcano {
v := &Volcano{}
for i := range inp {
v.rooms = append(v.rooms, StringToRoom(inp[i]))
}
for i := range v.rooms {
for _, valve := range v.rooms[i].RawTunnels {
v.rooms[i].Tunnels = append(v.rooms[i].Tunnels, v.FindRoom(valve))
}
}
return v
}
func NewVolcano(rooms []*Room, graph map[*Room]map[*Room]uint16) *Volcano {
v := Volcano{}
func (v *Volcano) CountSteps(from string, to string) int {
start, end := v.FindRoom(from), v.FindRoom(to)
if start == nil || end == nil {
fmt.Println("Couldn't find requested rooms:", from, ":", start, " ; ", to, ":", end)
return math.MaxInt
// pick valves with flow and starting point
for _, r := range rooms {
if r.Rate > 0 || r.Name == "AA" {
v.goodrooms = append(v.goodrooms, r)
}
}
return v.TrackStepCount(start, end, []*Room{})
}
func (v *Volcano) TrackStepCount(from *Room, to *Room, visited []*Room) int {
if from == to {
return 0
// assign bits
v.bitfield = make(map[*Room]uint16)
for idx, r := range v.goodrooms {
v.bitfield[r] = 1 << idx
}
minSteps := math.MaxInt
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 {
for _, r := range v.rooms {
if r.Valve == valve {
return r
// find start
for _, r := range v.goodrooms {
if r.Name == "AA" {
v.start = v.bitfield[r]
break
}
}
return nil
}
func IsRoomIn(room *Room, rooms []*Room) bool {
for i := range rooms {
if rooms[i] == room {
return true
// create slice for fast edge lookup
v.bitgraphs = make([]uint16, 0xffff)
for _, v1 := range v.goodrooms {
for _, v2 := range v.goodrooms {
v.bitgraphs[v.bitfield[v1]|v.bitfield[v2]] = graph[v1][v2]
}
}
return false
// create slice for fast node lookup
v.goodbits = make([][2]uint16, len(v.goodrooms))
for idx, r := range v.goodrooms {
v.goodbits[idx] = [2]uint16{v.bitfield[r], r.Rate}
}
return &v
}
type Room struct {
Valve string
FlowRate int
RawTunnels []string
Tunnels []*Room
Name string
Rate uint16
Edges string
}
func StringToRoom(s string) *Room {
room := &Room{}
r := strings.NewReader(s)
fmt.Fscanf(r, "Valve %s has flow rate=%d; tunnels lead to valve", &room.Valve, &room.FlowRate)
readTunnels := strings.Split(s, " valve")[1]
if readTunnels[0] == ' ' {
readTunnels = readTunnels[1:]
} else {
readTunnels = readTunnels[2:]
func parseRooms(inp []string) []*Room {
rooms := make([]*Room, len(inp))
for idx, line := range inp {
m := valveregexp.FindStringSubmatch(line)
i, _ := strconv.Atoi(m[2])
rooms[idx] = &Room{Name: m[1], Rate: uint16(i), Edges: m[3]}
}
room.RawTunnels = strings.Split(readTunnels, ", ")
return room
return rooms
}
func (r Room) String() string {
return r.Valve
}
func floydWarshall(valves []*Room) map[*Room]map[*Room]uint16 {
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 {
return fmt.Sprintf("Valve %s has flow rate=%d; tunnels lead to valves %v", r.Valve, r.FlowRate, r.RawTunnels)
for _, k := range valves {
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
• [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?
Advent of Code
br0xen (AoC++) 47*
--- 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
gave you. However, you don't see any Elves around; instead, the device is surrounded by elephants! They must have gotten
lost in these tunnels, and one of the elephants apparently figured out how to turn on the distress signal.
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
any Elves around; instead, the device is surrounded by elephants! They must have gotten lost in these tunnels, and one of the elephants apparently
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
handheld device; it reports mostly igneous rock, some ash, pockets of pressurized gas, magma... this isn't just a cave,
it's a volcano!
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
igneous rock, some ash, pockets of pressurized gas, magma... this isn't just a cave, 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
erupts, so you don't have time to go back out the way you came in.
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
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
such a system got into a volcano, 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 minute) and the tunnels you could use to move between the
valves.
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,
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
minute) and the tunnels you could use to move between the valves.
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 valve and one minute to follow any tunnel from one valve to another. What is the most
pressure you could release?
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
valve and one minute to follow any tunnel from one valve to another. What is the most pressure you could release?
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 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
0, so there's no point in 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 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 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 CC.
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
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
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
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
CC.
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 to release as much pressure as possible, so you'll need to be methodical. Instead,
consider this approach:
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
to release as much pressure as possible, so you'll need to be methodical. Instead, consider this approach:
== Minute 1 ==
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?
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
@ -196,7 +254,6 @@ References
. https://adventofcode.com/
. https://adventofcode.com/2022/about
. https://adventofcode.com/2022/events
. https://teespring.com/stores/advent-of-code
. https://adventofcode.com/2022/settings
. https://adventofcode.com/2022/auth/logout
. Advent of Code Supporter
@ -208,7 +265,5 @@ References
. https://adventofcode.com/2022/leaderboard
. https://adventofcode.com/2022/stats
. https://adventofcode.com/2022/sponsors
. https://sentry.io/
. https://adventofcode.com/2022
. 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);