aboutsummaryrefslogtreecommitdiffstats
path: root/day16
diff options
context:
space:
mode:
authorAn0nSaiko <porfeas12@gmail.com>2022-12-18 23:30:13 +0200
committerAn0nSaiko <porfeas12@gmail.com>2022-12-18 23:30:13 +0200
commit77c9806c3de6ee09130f2c5c2344b4ef054c1433 (patch)
tree61e2d2ef5dbdf0cc8253c1389596a946d886701b /day16
parentDay 17 (diff)
downloadaoc22-77c9806c3de6ee09130f2c5c2344b4ef054c1433.tar.gz
aoc22-77c9806c3de6ee09130f2c5c2344b4ef054c1433.zip
Day 18
Diffstat (limited to 'day16')
-rw-r--r--day16/solution.nim297
1 files changed, 155 insertions, 142 deletions
diff --git a/day16/solution.nim b/day16/solution.nim
index ae93568..66015d3 100644
--- a/day16/solution.nim
+++ b/day16/solution.nim
@@ -5,25 +5,26 @@ import tables
5import strformat 5import strformat
6import algorithm 6import algorithm
7import sets 7import sets
8import sugar
8 9
9type 10type
10 NodeData = tuple 11 NodeData = tuple
11 pressure: int 12 pressure: int
12 neighbors: seq[string] 13 neighbors: seq[int64]
13 14
14 Node = tuple 15 Node = tuple
15 id: string 16 id: int64
16 data: NodeData 17 data: NodeData
17 18
18 NodeGraph = Table[string, NodeData] 19 NodeGraph = Table[int64, NodeData]
19 20
20 ExtendedNodeData = tuple 21 ExtendedNodeData = tuple
21 pressure: int 22 pressure: int
22 neighbors: Table[string, int] 23 neighbors: Table[int64, int]
23 24
24 ExtendedNodeGraph = Table[string, ExtendedNodeData] 25 ExtendedNodeGraph = Table[int64, ExtendedNodeData]
25 26
26proc parseLine(line: string): Node = 27proc parseLine(line: string): auto =
27 let tokens = line.replace("Valve ") 28 let tokens = line.replace("Valve ")
28 .replace("has flow rate=") 29 .replace("has flow rate=")
29 .replace(re"; tunnels? leads? to valves?") 30 .replace(re"; tunnels? leads? to valves?")
@@ -35,145 +36,157 @@ proc parseFile(content: string): NodeGraph =
35 let lines = content.strip().splitLines() 36 let lines = content.strip().splitLines()
36 let nodes = map(lines, parseLine) 37 let nodes = map(lines, parseLine)
37 38
38 for node in nodes: 39 # Create stringID to intID mapping
39 result[node.id] = node.data 40 var nodeIDs: Table[string, int64]
40 41 for i, node in nodes:
41proc bfs(input: NodeGraph, src: string): Table[string, int] = 42 nodeIDs[node[0]] = 1 shl i
42 var q = @[(src, 0)] 43
43 result[src] = 0 44 echo nodeIDs
44 45 # for i, node in nodes:
45 while q.len() > 0: 46 # result[nodeIDs[nodes[0]]] = (node[1][0], map(node[1][1], (stringID) => nodeIDs[stringID]))
46 let (curr, pathLen) = q[0] 47
47 q.delete(0) 48# proc bfs(input: NodeGraph, src: string): Table[string, int] =
48 49# var q = @[(src, 0)]
49 for neighbor in input[curr].neighbors: 50# result[src] = 0
50 if result.contains(neighbor): 51#
51 continue 52# while q.len() > 0:
52 result[neighbor] = pathLen+1 53# let (curr, pathLen) = q[0]
53 q.add((neighbor, pathLen+1)) 54# q.delete(0)
54 55#
55proc setup(input: NodeGraph): ExtendedNodeGraph = 56# for neighbor in input[curr].neighbors:
56 for node in input.keys(): 57# if result.contains(neighbor):
57 # Exclude all 0 pressure nodes except the entry node "AA" 58# continue
58 if (input[node].pressure == 0 and node != "AA"): 59# result[neighbor] = pathLen+1
59 continue 60# q.add((neighbor, pathLen+1))
60 let allConnected = bfs(input, node) 61#
61 var filtConnected: Table[string, int] 62# proc setup(input: NodeGraph): ExtendedNodeGraph =
62 for conn in allConnected.keys(): 63# for node in input.keys():
63 if input[conn].pressure == 0: 64# # Exclude all 0 pressure nodes except the entry node "AA"
64 continue 65# if (input[node].pressure == 0 and node != "AA"):
65 filtConnected[conn] = allConnected[conn] 66# continue
66 67# let allConnected = bfs(input, node)
67 result[node] = (input[node].pressure, filtConnected) 68# var filtConnected: Table[string, int]
68 # echo fmt"{node} : {result[node]}" 69# for conn in allConnected.keys():
69 70# if input[conn].pressure == 0:
70type Agent = tuple 71# continue
71 valv: string 72# filtConnected[conn] = allConnected[conn]
72 time: int 73#
73 74# result[node] = (input[node].pressure, filtConnected)
74# Nodes with their neighbors 75# # echo fmt"{node} : {result[node]}"
75var Graph: ExtendedNodeGraph 76#
76# Node names 77# type Agent = tuple
77var nodes = newSeq[string]() 78# valv: string
78 79# time: int
79proc playing(agent: Agent, time: int): bool = 80#
80 agent.time == time 81# # Nodes with their neighbors
81 82# var Graph: ExtendedNodeGraph
82proc agentScores(agent: Agent, time: int): int = 83# # Node names
83 Graph[agent.valv].pressure * (time-1) 84# var nodes = newSeq[string]()
84 85#
86# proc playing(agent: Agent, time: int): bool =
87# agent.time == time
88#
89# proc agentScores(agent: Agent, time: int): int =
90# Graph[agent.valv].pressure * (time-1)
91#
85# type ValveSet = uint64 92# type ValveSet = uint64
93#
86# proc incl(set: var ValveSet, valve: uint64): void = 94# proc incl(set: var ValveSet, valve: uint64): void =
87# set = set or valve 95# set = set or valve
88 96#
89var part2 = false 97# proc contains(set: ValveSet, valve: uint64): bool =
90proc dfs(visited: HashSet[string], time: int, human, elephant: Agent): int = 98# return (set and valve) > 0
91 # echo fmt"time: {time}, human: {human}, elephant: {elephant}" 99#
92 let remainingValves = nodes.len() - visited.len() 100# var part2 = false
93 if time <= 1 or remainingValves == 0 or (part2 and human.valv == elephant.valv and remainingValves > 1): 101# proc dfs(visited: ValveSet, time: int, human, elephant: Agent): int =
94 return 0 102# # echo fmt"time: {time}, human: {human}, elephant: {elephant}"
95 103# let remainingValves = nodes.len() - visited.len()
96 let 104# if time <= 1 or remainingValves == 0 or (part2 and human.valv == elephant.valv and remainingValves > 1):
97 neighborsHuman = Graph[human.valv].neighbors 105# return 0
98 neighborsElephant = Graph[elephant.valv].neighbors 106#
99 var 107# let
100 # check for race 108# neighborsHuman = Graph[human.valv].neighbors
101 humanScore = if human.valv notin visited: human.agentScores(time) else: 0 109# neighborsElephant = Graph[elephant.valv].neighbors
102 elephantScore = if elephant.valv notin visited: elephant.agentScores(time) else: 0 110# var
103 111# # check for race
104 var bestNextScore = 0 112# humanScore = if human.valv notin visited: human.agentScores(time) else: 0
105 if human.playing(time) and elephant.playing(time): 113# elephantScore = if elephant.valv notin visited: elephant.agentScores(time) else: 0
106 for nextHuman in nodes: 114#
107 for nextElephant in nodes: 115# var bestNextScore = 0
108 if nextHuman in visited or nextElephant in visited: 116# if human.playing(time) and elephant.playing(time):
109 continue 117# for nextHuman in nodes:
110 let 118# for nextElephant in nodes:
111 nextTimeHuman = time - 1 - neighborsHuman[nextHuman] 119# if nextHuman in visited or nextElephant in visited:
112 nextTimeElephant = time - 1 - neighborsElephant[nextElephant] 120# continue
113 nextTime = max(nextTimeHuman, nextTimeElephant) 121# let
114 nextScore = dfs(union(visited, toHashSet(@[elephant.valv, human.valv])), nextTime, (nextHuman, nextTimeHuman), (nextElephant, nextTimeElephant)) 122# nextTimeHuman = time - 1 - neighborsHuman[nextHuman]
115 bestNextScore = max(bestNextScore, nextScore) 123# nextTimeElephant = time - 1 - neighborsElephant[nextElephant]
116 124# nextTime = max(nextTimeHuman, nextTimeElephant)
117 # elephant keeps his score only if he isn't in the same valve as human 125# nextScore = dfs(union(visited, toHashSet(@[elephant.valv, human.valv])), nextTime, (nextHuman, nextTimeHuman), (nextElephant, nextTimeElephant))
118 elephantScore = (if human != elephant: elephantScore else: 0) 126# bestNextScore = max(bestNextScore, nextScore)
119 return bestNextScore + humanScore + elephantScore 127#
120 128# # elephant keeps his score only if he isn't in the same valve as human
121 if human.playing(time): 129# elephantScore = (if human != elephant: elephantScore else: 0)
122 for nextHuman in nodes: 130# return bestNextScore + humanScore + elephantScore
123 if nextHuman in visited: 131#
124 continue 132# if human.playing(time):
125 let 133# for nextHuman in nodes:
126 nextTimeHuman = time - 1 - neighborsHuman[nextHuman] 134# if nextHuman in visited:
127 nextTime = max(nextTimeHuman, elephant.time) 135# continue
128 nextScore = dfs(union(visited, toHashSet(@[human.valv])), nextTime, (nextHuman, nextTimeHuman), elephant) 136# let
129 bestNextScore = max(bestNextScore, nextScore) 137# nextTimeHuman = time - 1 - neighborsHuman[nextHuman]
130 138# nextTime = max(nextTimeHuman, elephant.time)
131 # Check for race 139# nextScore = dfs(union(visited, toHashSet(@[human.valv])), nextTime, (nextHuman, nextTimeHuman), elephant)
132 return bestNextScore + humanScore 140# bestNextScore = max(bestNextScore, nextScore)
133 141#
134 if elephant.playing(time): 142# # Check for race
135 for nextElephant in nodes: 143# return bestNextScore + humanScore
136 if nextElephant in visited: 144#
137 continue 145# if elephant.playing(time):
138 let 146# for nextElephant in nodes:
139 nextTimeElephant = time - 1 - neighborsElephant[nextElephant] 147# if nextElephant in visited:
140 nextTime = max(human.time, nextTimeElephant) 148# continue
141 nextScore = dfs(union(visited, toHashSet(@[elephant.valv])), nextTime, human, (nextElephant, nextTimeElephant)) 149# let
142 bestNextScore = max(bestNextScore, nextScore) 150# nextTimeElephant = time - 1 - neighborsElephant[nextElephant]
143 151# nextTime = max(human.time, nextTimeElephant)
144 # Check for race 152# nextScore = dfs(union(visited, toHashSet(@[elephant.valv])), nextTime, human, (nextElephant, nextTimeElephant))
145 return bestNextScore + elephantScore 153# bestNextScore = max(bestNextScore, nextScore)
146 154#
147 assert(false) 155# # Check for race
148 156# return bestNextScore + elephantScore
149proc solve(initDelays: Table[string, int], time: int): int = 157#
150 158# assert(false)
151 if not part2: 159#
152 for human in nodes: 160# proc solve(initDelays: Table[string, int], time: int): int =
153 let 161#
154 humanStartTime = time - initDelays[human] 162# if not part2:
155 startTime = humanStartTime 163# for human in nodes:
156 result = max(result, dfs(initHashSet[string](), startTime, (human, humanStartTime), (human, -1))) 164# let
157 else: 165# humanStartTime = time - initDelays[human]
158 for i, human in nodes[0 ..< ^1]: 166# startTime = humanStartTime
159 for elephant in nodes[i+1 .. ^1]: 167# result = max(result, dfs(initHashSet[string](), startTime, (human, humanStartTime), (human, -1)))
160 let 168# else:
161 elephantStartTime = time - initDelays[elephant] 169# for i, human in nodes[0 ..< ^1]:
162 humanStartTime = time - initDelays[human] 170# for elephant in nodes[i+1 .. ^1]:
163 startTime = max(elephantStartTime, humanStartTime) 171# let
164 result = max(result, dfs(initHashSet[string](), startTime, (human, humanStartTime), (elephant, elephantStartTime))) 172# elephantStartTime = time - initDelays[elephant]
173# humanStartTime = time - initDelays[human]
174# startTime = max(elephantStartTime, humanStartTime)
175# result = max(result, dfs(initHashSet[string](), startTime, (human, humanStartTime), (elephant, elephantStartTime)))
176#
177#
165 178
166let content = readFile("./example.txt") 179let content = readFile("./example.txt")
167
168let input = parseFile(content) 180let input = parseFile(content)
169Graph = setup(input) 181echo input
170# Table of delays to get from starting node "AA" to current 182
171let initDelays = Graph["AA"].neighbors 183# # Table of delays to get from starting node "AA" to current
172Graph.del("AA") 184# let initDelays = Graph["AA"].neighbors
173 185# Graph.del("AA")
174for node in Graph.keys(): 186#
175 nodes.add(node) 187# for node in Graph.keys():
176 188# nodes.add(node)
177echo solve(initDelays, 30) 189#
178part2 = true 190# echo solve(initDelays, 30)
179echo solve(initDelays, 26) 191# part2 = true
192# echo solve(initDelays, 26)