Day 16
This commit is contained in:
219
day16/common/volcano.go
Normal file
219
day16/common/volcano.go
Normal file
@@ -0,0 +1,219 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
||||
type Valve struct {
|
||||
name string
|
||||
rate int
|
||||
tunnels map[*Valve]struct{}
|
||||
distances map[*Valve]int
|
||||
}
|
||||
|
||||
func (valve *Valve) GetBestPathFromValveWithHelper(otherValves map[*Valve]int, minutesLeft int, helperValve *Valve, helperMinutesLeft int) int {
|
||||
max := 0
|
||||
current := 0
|
||||
|
||||
if minutesLeft > 0 {
|
||||
current += (minutesLeft - 1) * valve.rate
|
||||
}
|
||||
if helperMinutesLeft > 0 {
|
||||
current += (helperMinutesLeft - 1) * helperValve.rate
|
||||
}
|
||||
|
||||
if minutesLeft > 0 || helperMinutesLeft > 0 {
|
||||
for relevantValve := range(otherValves) {
|
||||
done := false
|
||||
if minutesLeft <= 0 {
|
||||
done = true
|
||||
}
|
||||
if minutesLeft - valve.distances[relevantValve] <= 0 {
|
||||
relevantValve = valve
|
||||
minutesLeft = 0
|
||||
}
|
||||
|
||||
for relevantValve2 := range(otherValves) {
|
||||
helperDone := false
|
||||
if helperMinutesLeft <= 0 {
|
||||
helperDone = true
|
||||
}
|
||||
if helperMinutesLeft - helperValve.distances[relevantValve2] <= 0 {
|
||||
relevantValve2 = helperValve
|
||||
helperMinutesLeft = 0
|
||||
}
|
||||
|
||||
if relevantValve != relevantValve2 {
|
||||
currentRelevantValves := make(map[*Valve]int)
|
||||
for relevantValve3, relevantValveRate3 := range(otherValves) {
|
||||
if relevantValve != relevantValve3 && relevantValve2 != relevantValve3 {
|
||||
currentRelevantValves[relevantValve3] = relevantValveRate3
|
||||
}
|
||||
}
|
||||
currentMax := relevantValve.GetBestPathFromValveWithHelper(currentRelevantValves, minutesLeft - 1 - valve.distances[relevantValve],
|
||||
relevantValve2, helperMinutesLeft - 1 - helperValve.distances[relevantValve2])
|
||||
if currentMax > max {
|
||||
max = currentMax
|
||||
}
|
||||
} else if len(otherValves) == 1 {
|
||||
currentMax := relevantValve.GetBestPathFromValveWithHelper(make(map[*Valve]int), minutesLeft - 1 - valve.distances[relevantValve],
|
||||
helperValve, 0)
|
||||
if currentMax > max {
|
||||
max = currentMax
|
||||
}
|
||||
currentMax = valve.GetBestPathFromValveWithHelper(make(map[*Valve]int), 0,
|
||||
relevantValve2, helperMinutesLeft - 1 - helperValve.distances[relevantValve2])
|
||||
if currentMax > max {
|
||||
max = currentMax
|
||||
}
|
||||
}
|
||||
|
||||
if helperDone {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if done {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return max + current
|
||||
}
|
||||
|
||||
func (valve *Valve) GetBestPathFromValve(otherValves map[*Valve]int, minutesLeft int) int {
|
||||
if minutesLeft <= 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
current := (minutesLeft - 1) * valve.rate
|
||||
max := 0
|
||||
|
||||
for relevantValve := range(otherValves) {
|
||||
currentRelevantValves := make(map[*Valve]int)
|
||||
for relevantValve2, relevantValveRate2 := range(otherValves) {
|
||||
if relevantValve != relevantValve2 {
|
||||
currentRelevantValves[relevantValve2] = relevantValveRate2
|
||||
}
|
||||
}
|
||||
currentMax := relevantValve.GetBestPathFromValve(currentRelevantValves, minutesLeft - 1 - valve.distances[relevantValve])
|
||||
if currentMax > max {
|
||||
max = currentMax
|
||||
}
|
||||
}
|
||||
|
||||
return max + current
|
||||
}
|
||||
|
||||
|
||||
type Volcano struct {
|
||||
valves []*Valve
|
||||
current *Valve
|
||||
rate int
|
||||
pressure int
|
||||
minutesLeft int
|
||||
}
|
||||
|
||||
func (volcano *Volcano) GetBestPath(minutesLeft int, helper bool) int {
|
||||
relevantValves := make(map[*Valve]int)
|
||||
for valve := range volcano.valves {
|
||||
if volcano.valves[valve].rate > 0 {
|
||||
relevantValves[volcano.valves[valve]] = volcano.valves[valve].rate
|
||||
}
|
||||
}
|
||||
|
||||
if helper {
|
||||
return volcano.current.GetBestPathFromValveWithHelper(relevantValves, minutesLeft + 1, volcano.current, minutesLeft + 1)
|
||||
} else {
|
||||
return volcano.current.GetBestPathFromValve(relevantValves, minutesLeft + 1)
|
||||
}
|
||||
}
|
||||
|
||||
func (volcano *Volcano) ComputeDistances() bool {
|
||||
changesFound := false
|
||||
for valveSource := range volcano.valves {
|
||||
for valveTarget1 := range volcano.valves[valveSource].distances {
|
||||
for valveTarget2 := range volcano.valves[valveSource].distances {
|
||||
d, ok := valveTarget1.distances[valveTarget2]
|
||||
newDistance := volcano.valves[valveSource].distances[valveTarget1] +
|
||||
volcano.valves[valveSource].distances[valveTarget2]
|
||||
if !ok || newDistance < d {
|
||||
valveTarget1.distances[valveTarget2] = newDistance
|
||||
valveTarget2.distances[valveTarget1] = newDistance
|
||||
changesFound = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return changesFound
|
||||
}
|
||||
|
||||
func (volcano *Volcano) Print() {
|
||||
for i := range(volcano.valves) {
|
||||
fmt.Print(volcano.valves[i].name)
|
||||
fmt.Print(": ")
|
||||
fmt.Println(volcano.valves[i].rate)
|
||||
for valve, d := range(volcano.valves[i].distances) {
|
||||
fmt.Print(" ")
|
||||
fmt.Print(valve.name)
|
||||
fmt.Print(": ")
|
||||
fmt.Println(d)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func Parse(scanner bufio.Scanner) Volcano {
|
||||
volcano := Volcano{}
|
||||
volcano.valves = []*Valve{}
|
||||
destinations := make(map[string][]string)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
splittedLine := strings.Split(line, " ")
|
||||
name := splittedLine[1]
|
||||
rate, _ := strconv.Atoi(splittedLine[4][5:len(splittedLine[4])-1])
|
||||
destinations[name] = []string{}
|
||||
for i := 9; i < len(splittedLine); i++ {
|
||||
destinations[name] = append(destinations[name], splittedLine[i][0:2])
|
||||
}
|
||||
volcano.valves = append(volcano.valves, &Valve{name, rate, map[*Valve]struct{}{}, make(map[*Valve]int)})
|
||||
}
|
||||
|
||||
for valveName, currDestinations := range(destinations) {
|
||||
var valveSource *Valve
|
||||
for i := range volcano.valves {
|
||||
if volcano.valves[i].name == valveName {
|
||||
valveSource = volcano.valves[i]
|
||||
valveSource.distances[valveSource] = 0
|
||||
break
|
||||
}
|
||||
}
|
||||
for _, destination := range currDestinations {
|
||||
var valveDestination *Valve
|
||||
for i := range volcano.valves {
|
||||
if volcano.valves[i].name == destination {
|
||||
valveDestination = volcano.valves[i]
|
||||
}
|
||||
}
|
||||
valveSource.tunnels[valveDestination] = struct{}{}
|
||||
valveSource.distances[valveDestination] = 1
|
||||
}
|
||||
}
|
||||
|
||||
for i := range(volcano.valves) {
|
||||
if volcano.valves[i].name == "AA" {
|
||||
volcano.current = volcano.valves[i]
|
||||
}
|
||||
}
|
||||
volcano.minutesLeft = 30
|
||||
|
||||
for volcano.ComputeDistances() {}
|
||||
|
||||
return volcano
|
||||
}
|
||||
14
day16/ex1/main.go
Normal file
14
day16/ex1/main.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"aoc2022/day16/common"
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
volcano := common.Parse(*bufio.NewScanner(os.Stdin))
|
||||
|
||||
fmt.Println(volcano.GetBestPath(30, false))
|
||||
}
|
||||
14
day16/ex2/main.go
Normal file
14
day16/ex2/main.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"aoc2022/day16/common"
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
volcano := common.Parse(*bufio.NewScanner(os.Stdin))
|
||||
|
||||
fmt.Println(volcano.GetBestPath(26, true))
|
||||
}
|
||||
Reference in New Issue
Block a user