AOC2022/day16/day16.go
2022-12-17 21:48:02 +01:00

268 lines
9.0 KiB
Go

package main
import (
"AOC2022/helper"
"fmt"
"sort"
"strconv"
"strings"
)
type Valve struct {
id string
flowRate int
routes map[string]int
cost int
before string
}
type Route struct {
activeValves [2]string
remainingTime [2]int
remainingValves []string
pastMoves []string
releasedPressure int
}
func main() {
//args := os.Args[1:]
lines := helper.ReadTextFile("day16/input")
valves := getValves(lines)
valvesWithFlowRate := getValvesWithFlowRate(valves)
valvesWithFlowRate = append(valvesWithFlowRate, "AA")
valvesCopy := deepCopyMap(valves)
for i, activeValve := range valvesWithFlowRate {
routes := make(map[string]int)
for j, valve := range valvesWithFlowRate {
if i != j {
tmpValves := deepCopyMap(valvesCopy)
routeLenght := getRouteLength(activeValve, valve, tmpValves)
routes[valve] = routeLenght
}
}
entry := valves[activeValve]
entry.routes = routes
valves[activeValve] = entry
}
currentValve := "AA"
remainingValves := valvesWithFlowRate[:len(valvesWithFlowRate)-1]
part2(currentValve, remainingValves, valves)
}
func part1(currentValve string, remainingValves []string, valves map[string]Valve) {
activeRountes := make(map[string]Route)
activeRountes[stringSliceToString(remainingValves)] = Route{[2]string{currentValve}, [2]int{30}, remainingValves, []string{}, 0}
endedRoutes := []Route{}
for len(activeRountes) > 0 {
stepFindSolution(&valves, &activeRountes, &endedRoutes)
}
highestPressureRelease := 0
for _, route := range endedRoutes {
if route.releasedPressure > highestPressureRelease {
highestPressureRelease = route.releasedPressure
}
}
fmt.Println(highestPressureRelease)
}
func part2(currentValve string, remainingValves []string, valves map[string]Valve) {
activeRountes := make(map[string]Route)
activeRountes[stringSliceToString(remainingValves)] = Route{[2]string{currentValve, currentValve}, [2]int{26, 26}, remainingValves, []string{}, 0}
endedRoutes := []Route{}
for len(activeRountes) > 0 {
stepFindSolution(&valves, &activeRountes, &endedRoutes)
}
highestPressureReleaseRoute := Route{}
highestPressureReleaseRoute.releasedPressure = 0
for _, route := range endedRoutes {
if route.releasedPressure > highestPressureReleaseRoute.releasedPressure {
highestPressureReleaseRoute = route
}
}
fmt.Println(highestPressureReleaseRoute.releasedPressure)
}
func stringSliceToString(slice []string) string {
str := ""
sort.Strings(slice)
for i := 0; i < len(slice); i++ {
str += slice[i]
}
return str
}
func falseSolutionPart1(currentValve string, remainingValves []string, valves map[string]Valve) {
fmt.Println(currentValve)
fmt.Println(remainingValves)
remainingTime := 30
sumReleasedPressure := 0
for len(remainingValves) > 0 && remainingTime > 0 {
getNextStep(&remainingValves, valves, &currentValve, &remainingTime, &sumReleasedPressure)
fmt.Println(currentValve)
}
fmt.Println(sumReleasedPressure)
}
func getNextStep(remainingValves *[]string, valves map[string]Valve, currentValve *string, remainingTime *int, sumReleasedPressure *int) {
bestValve := -1
bestValue := 0
for i, remainingValve := range *remainingValves {
movingTimeCost := valves[*currentValve].routes[remainingValve]
openingTimeCost := 1
flowrate := valves[remainingValve].flowRate
possibleGainedPressureReduction := (*remainingTime - openingTimeCost - movingTimeCost) * flowrate
if possibleGainedPressureReduction > bestValue {
bestValue = possibleGainedPressureReduction
bestValve = i
}
}
if bestValve == -1 {
*remainingTime = 0
return
}
*sumReleasedPressure += bestValue
*remainingTime -= (valves[*currentValve].routes[(*remainingValves)[bestValve]] + 1)
*currentValve = (*remainingValves)[bestValve]
helper.Remove(remainingValves, bestValve)
}
func stepFindSolution(valves *map[string]Valve, remainingRoutes *map[string]Route, endedRoutes *[]Route) {
key := get_some_key(*remainingRoutes)
currentRoute := (*remainingRoutes)[key]
delete(*remainingRoutes, key)
directions1 := getDirections(valves, currentRoute.remainingValves, currentRoute.activeValves[0], currentRoute.remainingTime[0])
directions2 := getDirections(valves, currentRoute.remainingValves, currentRoute.activeValves[1], currentRoute.remainingTime[1])
if len(directions1) == 0 && len(directions2) == 0 {
*endedRoutes = append(*endedRoutes, currentRoute)
}
for remainingValve, timeCost := range directions1 {
newRemainingTime, possibleGainedPressureReduction := getNewTimeAndRemainingValves(valves, remainingValve, currentRoute.remainingTime[0], timeCost)
newRemainingValves := helper.RemoveElement(currentRoute.remainingValves, remainingValve)
newReleasedPressure := currentRoute.releasedPressure + possibleGainedPressureReduction
newPastMoves := append(currentRoute.pastMoves, remainingValve)
value, ok := (*remainingRoutes)[stringSliceToString(newRemainingValves)]
if !ok || newReleasedPressure > value.releasedPressure {
(*remainingRoutes)[stringSliceToString(newRemainingValves)] = Route{[2]string{remainingValve, currentRoute.activeValves[1]}, [2]int{newRemainingTime, currentRoute.remainingTime[1]}, newRemainingValves, newPastMoves, newReleasedPressure}
}
}
for remainingValve, timeCost := range directions2 {
newRemainingTime, possibleGainedPressureReduction := getNewTimeAndRemainingValves(valves, remainingValve, currentRoute.remainingTime[1], timeCost)
newRemainingValves := helper.RemoveElement(currentRoute.remainingValves, remainingValve)
newReleasedPressure := currentRoute.releasedPressure + possibleGainedPressureReduction
newPastMoves := append(currentRoute.pastMoves, remainingValve)
value, ok := (*remainingRoutes)[stringSliceToString(newRemainingValves)]
if !ok || newReleasedPressure > value.releasedPressure {
(*remainingRoutes)[stringSliceToString(newRemainingValves)] = Route{[2]string{currentRoute.activeValves[0], remainingValve}, [2]int{currentRoute.remainingTime[0], newRemainingTime}, newRemainingValves, newPastMoves, newReleasedPressure}
}
}
}
func getNewTimeAndRemainingValves(valves *map[string]Valve, remainingValve string, remainingTime int, timeCost int) (int, int) {
flowrate := (*valves)[remainingValve].flowRate
newRemainingTime := remainingTime - timeCost
possibleGainedPressureReduction := newRemainingTime * flowrate
return newRemainingTime, possibleGainedPressureReduction
}
func getDirections(valves *map[string]Valve, remainingValves []string, activeValve string, remainingTime int) map[string]int {
directions := make(map[string]int)
for _, remainingValve := range remainingValves {
movingTimeCost := (*valves)[activeValve].routes[remainingValve]
openingTimeCost := 1
if remainingTime > movingTimeCost+openingTimeCost {
directions[remainingValve] = movingTimeCost + openingTimeCost
}
}
return directions
}
func deepCopyMap(valves map[string]Valve) map[string]Valve {
tmpValves := make(map[string]Valve)
for k, v := range valves {
tmpValves[k] = v
}
return tmpValves
}
func getValves(lines []string) map[string]Valve {
valves := make(map[string]Valve)
for _, line := range lines {
id := line[6:8]
flowrate := helper.RemoveError(strconv.Atoi(strings.Split(line[23:], ";")[0]))
routesStrings := strings.Split(strings.Split(line[23:], ";")[1][24:], ", ")
routes := make(map[string]int)
for _, routeString := range routesStrings {
routes[routeString] = 1
}
valves[id] = Valve{id, flowrate, routes, 0, ""}
}
return valves
}
func getValvesWithFlowRate(valves map[string]Valve) []string {
valvesWithFlowRate := []string{}
for key, val := range valves {
if val.flowRate > 0 {
valvesWithFlowRate = append(valvesWithFlowRate, key)
}
}
return valvesWithFlowRate
}
func getRouteLength(valve1, valve2 string, valves map[string]Valve) int {
activeValves := make(map[string]struct{})
activeValves[valve1] = struct{}{}
return getBestRouteLength(activeValves, valves, valve2)
}
func getBestRouteLength(activeValves map[string]struct{}, valves map[string]Valve, endValve string) int {
for len(activeValves) > 0 {
step(&valves, &activeValves)
}
return valves[endValve].cost
}
func step(valves *map[string]Valve, activeValves *map[string]struct{}) {
valve := get_some_key(*activeValves)
delete(*activeValves, valve)
currentValve := (*valves)[valve]
currentFieldSumCost := currentValve.cost
directions := currentValve.routes
for _, v := range *valves {
lenthConnectionToCurrentValve := 0
for connectedValve, length := range v.routes {
if connectedValve == currentValve.id {
lenthConnectionToCurrentValve = length
}
}
if lenthConnectionToCurrentValve > 0 {
directions[v.id] = lenthConnectionToCurrentValve
}
}
for nextValve, _ := range directions {
cost := 1 + currentFieldSumCost
if nextValve != currentValve.before {
if (*valves)[nextValve].cost > cost || (*valves)[nextValve].cost == 0 {
entry := (*valves)[nextValve]
entry.cost = cost
entry.before = valve
(*valves)[nextValve] = entry
(*activeValves)[nextValve] = struct{}{}
}
}
}
}
func get_some_key[T any](m map[string]T) string {
for k := range m {
return k
}
return ""
}