2022-12-17 18:02:58 +01:00
package main
import (
"AOC2022/helper"
"fmt"
2022-12-17 21:48:02 +01:00
"sort"
2022-12-17 18:02:58 +01:00
"strconv"
"strings"
)
type Valve struct {
id string
flowRate int
routes map [ string ] int
cost int
before string
}
2022-12-17 19:32:19 +01:00
type Route struct {
2022-12-17 20:53:14 +01:00
activeValves [ 2 ] string
remainingTime [ 2 ] int
2022-12-17 19:32:19 +01:00
remainingValves [ ] string
pastMoves [ ] string
releasedPressure int
}
2022-12-17 18:02:58 +01:00
func main ( ) {
//args := os.Args[1:]
2022-12-17 19:32:19 +01:00
lines := helper . ReadTextFile ( "day16/input" )
2022-12-17 18:02:58 +01:00
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 ]
2022-12-17 20:53:14 +01:00
part2 ( currentValve , remainingValves , valves )
}
func part1 ( currentValve string , remainingValves [ ] string , valves map [ string ] Valve ) {
2022-12-17 21:48:02 +01:00
activeRountes := make ( map [ string ] Route )
activeRountes [ stringSliceToString ( remainingValves ) ] = Route { [ 2 ] string { currentValve } , [ 2 ] int { 30 } , remainingValves , [ ] string { } , 0 }
2022-12-17 19:32:19 +01:00
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 )
}
2022-12-17 20:53:14 +01:00
func part2 ( currentValve string , remainingValves [ ] string , valves map [ string ] Valve ) {
2022-12-17 21:48:02 +01:00
activeRountes := make ( map [ string ] Route )
activeRountes [ stringSliceToString ( remainingValves ) ] = Route { [ 2 ] string { currentValve , currentValve } , [ 2 ] int { 26 , 26 } , remainingValves , [ ] string { } , 0 }
2022-12-17 20:53:14 +01:00
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 )
}
2022-12-17 21:48:02 +01:00
func stringSliceToString ( slice [ ] string ) string {
str := ""
sort . Strings ( slice )
for i := 0 ; i < len ( slice ) ; i ++ {
str += slice [ i ]
}
return str
}
2022-12-17 19:32:19 +01:00
func falseSolutionPart1 ( currentValve string , remainingValves [ ] string , valves map [ string ] Valve ) {
fmt . Println ( currentValve )
fmt . Println ( remainingValves )
2022-12-17 18:02:58 +01:00
remainingTime := 30
sumReleasedPressure := 0
2022-12-17 19:32:19 +01:00
for len ( remainingValves ) > 0 && remainingTime > 0 {
getNextStep ( & remainingValves , valves , & currentValve , & remainingTime , & sumReleasedPressure )
fmt . Println ( currentValve )
}
fmt . Println ( sumReleasedPressure )
2022-12-17 18:02:58 +01:00
}
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
}
}
2022-12-17 19:32:19 +01:00
if bestValve == - 1 {
* remainingTime = 0
return
}
2022-12-17 18:02:58 +01:00
* sumReleasedPressure += bestValue
* remainingTime -= ( valves [ * currentValve ] . routes [ ( * remainingValves ) [ bestValve ] ] + 1 )
* currentValve = ( * remainingValves ) [ bestValve ]
helper . Remove ( remainingValves , bestValve )
}
2022-12-17 21:48:02 +01:00
func stepFindSolution ( valves * map [ string ] Valve , remainingRoutes * map [ string ] Route , endedRoutes * [ ] Route ) {
key := get_some_key ( * remainingRoutes )
currentRoute := ( * remainingRoutes ) [ key ]
delete ( * remainingRoutes , key )
2022-12-17 19:32:19 +01:00
2022-12-17 20:53:14 +01:00
directions1 := getDirections ( valves , currentRoute . remainingValves , currentRoute . activeValves [ 0 ] , currentRoute . remainingTime [ 0 ] )
directions2 := getDirections ( valves , currentRoute . remainingValves , currentRoute . activeValves [ 1 ] , currentRoute . remainingTime [ 1 ] )
2022-12-17 21:48:02 +01:00
if len ( directions1 ) == 0 && len ( directions2 ) == 0 {
2022-12-17 19:32:19 +01:00
* endedRoutes = append ( * endedRoutes , currentRoute )
}
2022-12-17 21:48:02 +01:00
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 }
2022-12-17 20:53:14 +01:00
}
}
2022-12-17 21:48:02 +01:00
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 }
}
}
2022-12-17 20:53:14 +01:00
}
2022-12-17 21:48:02 +01:00
func getNewTimeAndRemainingValves ( valves * map [ string ] Valve , remainingValve string , remainingTime int , timeCost int ) ( int , int ) {
2022-12-17 20:53:14 +01:00
flowrate := ( * valves ) [ remainingValve ] . flowRate
2022-12-17 21:48:02 +01:00
newRemainingTime := remainingTime - timeCost
2022-12-17 20:53:14 +01:00
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
}
2022-12-17 19:32:19 +01:00
}
2022-12-17 20:53:14 +01:00
return directions
2022-12-17 19:32:19 +01:00
}
2022-12-17 18:02:58 +01:00
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
2022-12-17 19:32:19 +01:00
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
}
}
2022-12-17 18:02:58 +01:00
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 { } { }
}
}
}
}
2022-12-17 21:48:02 +01:00
func get_some_key [ T any ] ( m map [ string ] T ) string {
2022-12-17 18:02:58 +01:00
for k := range m {
return k
}
return ""
}