aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAn0nSaiko <porfeas12@gmail.com>2022-12-17 09:36:15 +0200
committerAn0nSaiko <porfeas12@gmail.com>2022-12-17 09:36:15 +0200
commitbdd738d805a7008382ae26460bc12523ef2d4a3e (patch)
treeeb862e2e7678548104d288068f038109fc5f5452
parentDay 16 (part1) (diff)
downloadaoc22-bdd738d805a7008382ae26460bc12523ef2d4a3e.tar.gz
aoc22-bdd738d805a7008382ae26460bc12523ef2d4a3e.zip
Day 16 (part1 & part2). Part2 is too slow and only works for the example
-rw-r--r--day16/solution.nim145
1 files changed, 103 insertions, 42 deletions
diff --git a/day16/solution.nim b/day16/solution.nim
index b6d39e6..ae93568 100644
--- a/day16/solution.nim
+++ b/day16/solution.nim
@@ -4,6 +4,7 @@ import re
4import tables 4import tables
5import strformat 5import strformat
6import algorithm 6import algorithm
7import sets
7 8
8type 9type
9 NodeData = tuple 10 NodeData = tuple
@@ -66,53 +67,113 @@ proc setup(input: NodeGraph): ExtendedNodeGraph =
66 result[node] = (input[node].pressure, filtConnected) 67 result[node] = (input[node].pressure, filtConnected)
67 # echo fmt"{node} : {result[node]}" 68 # echo fmt"{node} : {result[node]}"
68 69
70type Agent = tuple
71 valv: string
72 time: int
69 73
70var dp: Table[string, int] 74# Nodes with their neighbors
71proc normalize(visited: string): string = 75var Graph: ExtendedNodeGraph
72 var s: seq[string] 76# Node names
73 for i in countup(0, visited.len()-1, 2): 77var nodes = newSeq[string]()
74 s.add(visited[i..i+1])
75 result = s.sorted(system.cmp[string]).join()
76 78
77proc dfs(input: ExtendedNodeGraph, src: string, visited: string, time: int): int = 79proc playing(agent: Agent, time: int): bool =
78 if time <= 1 or visited.len() == input.len(): 80 agent.time == time
79 return 0
80 81
81 # if dp.contains(visited): 82proc agentScores(agent: Agent, time: int): int =
82 # return dp[visited] 83 Graph[agent.valv].pressure * (time-1)
83 84
84 let visitedNorm = visited.normalize() 85# type ValveSet = uint64
85 let selfScore = (time-1) * input[src].pressure 86# proc incl(set: var ValveSet, valve: uint64): void =
86 var maxSubscore = 0 87# set = set or valve
87 var maxNeighbor = "undefined" 88
88 # echo fmt"{src}({selfScore}): " 89var part2 = false
89 for neighbor in input[src].neighbors.keys(): 90proc dfs(visited: HashSet[string], time: int, human, elephant: Agent): int =
90 if neighbor in visited: 91 # echo fmt"time: {time}, human: {human}, elephant: {elephant}"
91 continue 92 let remainingValves = nodes.len() - visited.len()
92 let distance = input[src].neighbors[neighbor] 93 if time <= 1 or remainingValves == 0 or (part2 and human.valv == elephant.valv and remainingValves > 1):
93 let subScore = dfs(input, neighbor, visitedNorm & neighbor, time - 1 - distance) 94 return 0
94 if subScore > maxSubscore: 95
95 maxSubscore = subScore 96 let
96 maxNeighbor = neighbor 97 neighborsHuman = Graph[human.valv].neighbors
97 98 neighborsElephant = Graph[elephant.valv].neighbors
98 # echo fmt"{src}({selfScore}) => {maxNeighbor}({maxSubscore})" 99 var
99 result = selfScore + maxSubscore 100 # check for race
100 # dp[visitedNorm & maxNeighbor] = result 101 humanScore = if human.valv notin visited: human.agentScores(time) else: 0
101 # echo result 102 elephantScore = if elephant.valv notin visited: elephant.agentScores(time) else: 0
102 103
103proc solve(input: NodeGraph, time: int): int = 104 var bestNextScore = 0
104 let completeGraph = setup(input) 105 if human.playing(time) and elephant.playing(time):
105 # Table of delays to get from starting node "AA" to current 106 for nextHuman in nodes:
106 let initDelays = completeGraph["AA"].neighbors 107 for nextElephant in nodes:
107 108 if nextHuman in visited or nextElephant in visited:
108 for node in completeGraph.keys(): 109 continue
109 if node == "AA": 110 let
110 continue 111 nextTimeHuman = time - 1 - neighborsHuman[nextHuman]
111 let startTime = time - initDelays[node] 112 nextTimeElephant = time - 1 - neighborsElephant[nextElephant]
112 result = max(result, dfs(completeGraph, node, node, startTime)) 113 nextTime = max(nextTimeHuman, nextTimeElephant)
113 echo fmt"{node}({startTime}) : {result}" 114 nextScore = dfs(union(visited, toHashSet(@[elephant.valv, human.valv])), nextTime, (nextHuman, nextTimeHuman), (nextElephant, nextTimeElephant))
115 bestNextScore = max(bestNextScore, nextScore)
116
117 # elephant keeps his score only if he isn't in the same valve as human
118 elephantScore = (if human != elephant: elephantScore else: 0)
119 return bestNextScore + humanScore + elephantScore
120
121 if human.playing(time):
122 for nextHuman in nodes:
123 if nextHuman in visited:
124 continue
125 let
126 nextTimeHuman = time - 1 - neighborsHuman[nextHuman]
127 nextTime = max(nextTimeHuman, elephant.time)
128 nextScore = dfs(union(visited, toHashSet(@[human.valv])), nextTime, (nextHuman, nextTimeHuman), elephant)
129 bestNextScore = max(bestNextScore, nextScore)
130
131 # Check for race
132 return bestNextScore + humanScore
133
134 if elephant.playing(time):
135 for nextElephant in nodes:
136 if nextElephant in visited:
137 continue
138 let
139 nextTimeElephant = time - 1 - neighborsElephant[nextElephant]
140 nextTime = max(human.time, nextTimeElephant)
141 nextScore = dfs(union(visited, toHashSet(@[elephant.valv])), nextTime, human, (nextElephant, nextTimeElephant))
142 bestNextScore = max(bestNextScore, nextScore)
143
144 # Check for race
145 return bestNextScore + elephantScore
146
147 assert(false)
148
149proc solve(initDelays: Table[string, int], time: int): int =
150
151 if not part2:
152 for human in nodes:
153 let
154 humanStartTime = time - initDelays[human]
155 startTime = humanStartTime
156 result = max(result, dfs(initHashSet[string](), startTime, (human, humanStartTime), (human, -1)))
157 else:
158 for i, human in nodes[0 ..< ^1]:
159 for elephant in nodes[i+1 .. ^1]:
160 let
161 elephantStartTime = time - initDelays[elephant]
162 humanStartTime = time - initDelays[human]
163 startTime = max(elephantStartTime, humanStartTime)
164 result = max(result, dfs(initHashSet[string](), startTime, (human, humanStartTime), (elephant, elephantStartTime)))
114 165
115let content = readFile("./example.txt") 166let content = readFile("./example.txt")
116 167
117let input = parseFile(content) 168let input = parseFile(content)
118echo solve(input, 30) 169Graph = setup(input)
170# Table of delays to get from starting node "AA" to current
171let initDelays = Graph["AA"].neighbors
172Graph.del("AA")
173
174for node in Graph.keys():
175 nodes.add(node)
176
177echo solve(initDelays, 30)
178part2 = true
179echo solve(initDelays, 26)