From 4c89c9a42315541ece368085c519dfcda81ded69 Mon Sep 17 00:00:00 2001 From: RhiobeT Date: Sat, 17 Dec 2022 19:07:12 +0100 Subject: [PATCH] Day 16 --- day16/common/volcano.go | 219 ++++++++++++++++++++++++++++++++++++++++ day16/ex1/main.go | 14 +++ day16/ex2/main.go | 14 +++ 3 files changed, 247 insertions(+) create mode 100644 day16/common/volcano.go create mode 100644 day16/ex1/main.go create mode 100644 day16/ex2/main.go diff --git a/day16/common/volcano.go b/day16/common/volcano.go new file mode 100644 index 0000000..c4eb996 --- /dev/null +++ b/day16/common/volcano.go @@ -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 +} diff --git a/day16/ex1/main.go b/day16/ex1/main.go new file mode 100644 index 0000000..84741ac --- /dev/null +++ b/day16/ex1/main.go @@ -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)) +} diff --git a/day16/ex2/main.go b/day16/ex2/main.go new file mode 100644 index 0000000..e3c85a0 --- /dev/null +++ b/day16/ex2/main.go @@ -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)) +}