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 "" }