This commit is contained in:
2022-12-17 19:07:12 +01:00
parent cc58326f8c
commit 4c89c9a423
3 changed files with 247 additions and 0 deletions

219
day16/common/volcano.go Normal file
View 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
}