280 lines
9.5 KiB
Go
280 lines
9.5 KiB
Go
package main
|
|
|
|
import (
|
|
"AOC2022/helper"
|
|
"fmt"
|
|
"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 := []Route{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 := []Route{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 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, ¤tValve, &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 *[]Route, endedRoutes *[]Route) {
|
|
currentRoute := (*remainingRoutes)[len(*remainingRoutes)-1]
|
|
*remainingRoutes = (*remainingRoutes)[:len(*remainingRoutes)-1]
|
|
|
|
directions1 := getDirections(valves, currentRoute.remainingValves, currentRoute.activeValves[0], currentRoute.remainingTime[0])
|
|
directions2 := getDirections(valves, currentRoute.remainingValves, currentRoute.activeValves[1], currentRoute.remainingTime[1])
|
|
directionPairs := [][2]map[string]int{}
|
|
for valve1, cost1 := range directions1 {
|
|
if len(directions2) == 0 {
|
|
direction1 := map[string]int{valve1: cost1}
|
|
directionPairs = append(directionPairs, [2]map[string]int{direction1})
|
|
}
|
|
for valve2, cost2 := range directions2 {
|
|
if valve1 != valve2 {
|
|
direction1 := map[string]int{valve1: cost1}
|
|
direction2 := map[string]int{valve2: cost2}
|
|
directionPairs = append(directionPairs, [2]map[string]int{direction1, direction2})
|
|
}
|
|
}
|
|
}
|
|
if len(directionPairs) == 0 {
|
|
*endedRoutes = append(*endedRoutes, currentRoute)
|
|
}
|
|
|
|
for _, pair := range directionPairs {
|
|
newRoute := Route{}
|
|
newPastMoves := currentRoute.pastMoves
|
|
newReleasedPressure := currentRoute.releasedPressure
|
|
newRemainingValves := currentRoute.remainingValves
|
|
for remainingValve, timeCost := range pair[0] {
|
|
newRemainingTime1, possibleGainedPressureReduction1 := getNewTimeAndRemainingValves(valves, remainingValve, currentRoute, timeCost)
|
|
newReleasedPressure += possibleGainedPressureReduction1
|
|
newPastMoves = append(newPastMoves, remainingValve)
|
|
newRemainingValves = helper.RemoveElement(newRemainingValves, remainingValve)
|
|
newRoute.remainingTime[0] = newRemainingTime1
|
|
newRoute.activeValves[0] = remainingValve
|
|
}
|
|
for remainingValve, timeCost := range pair[1] {
|
|
newRemainingTime2, possibleGainedPressureReduction2 := getNewTimeAndRemainingValves(valves, remainingValve, currentRoute, timeCost)
|
|
newReleasedPressure += possibleGainedPressureReduction2
|
|
newPastMoves = append(newPastMoves, remainingValve)
|
|
newRemainingValves = helper.RemoveElement(newRemainingValves, remainingValve)
|
|
newRoute.remainingTime[1] = newRemainingTime2
|
|
newRoute.activeValves[1] = remainingValve
|
|
}
|
|
newRoute.pastMoves = newPastMoves
|
|
newRoute.releasedPressure = newReleasedPressure
|
|
newRoute.remainingValves = newRemainingValves
|
|
*remainingRoutes = append(*remainingRoutes, newRoute)
|
|
}
|
|
|
|
//for remainingValve, timeCost := range directions1 {
|
|
// newRemainingTime, possibleGainedPressureReduction := getNewTimeAndRemainingValves(valves, remainingValve, currentRoute, timeCost)
|
|
// newRemainingValves := helper.RemoveElement(currentRoute.remainingValves, remainingValve)
|
|
// newReleasedPressure := currentRoute.releasedPressure + possibleGainedPressureReduction
|
|
// newPastMoves := append(currentRoute.pastMoves, remainingValve)
|
|
// *remainingRoutes = append(*remainingRoutes, Route{[2]string{remainingValve}, [2]int{newRemainingTime}, newRemainingValves, newPastMoves, newReleasedPressure})
|
|
//}
|
|
}
|
|
|
|
func getNewTimeAndRemainingValves(valves *map[string]Valve, remainingValve string, currentRoute Route, timeCost int) (int, int) {
|
|
flowrate := (*valves)[remainingValve].flowRate
|
|
newRemainingTime := currentRoute.remainingTime[0] - 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(m map[string]struct{}) string {
|
|
for k := range m {
|
|
return k
|
|
}
|
|
return ""
|
|
}
|