|
|
|
import queue
|
|
|
|
|
|
|
|
MAX_STEPS = 26
|
|
|
|
|
|
|
|
q = queue.PriorityQueue()
|
|
|
|
valves = {}
|
|
|
|
valvesConsider = {}
|
|
|
|
distanceMap = {}
|
|
|
|
eliminated = {}
|
|
|
|
numTotalSteps = 0
|
|
|
|
|
|
|
|
class Valve():
|
|
|
|
def __init__(self, flowRate, tunnels, name):
|
|
|
|
self.flowRate = flowRate
|
|
|
|
self.tunnels = tunnels
|
|
|
|
self.name = name
|
|
|
|
|
|
|
|
def getFlowrate(self):
|
|
|
|
return self.flowRate
|
|
|
|
|
|
|
|
def genDistanceMap(self):
|
|
|
|
nextValves = queue.PriorityQueue()
|
|
|
|
nextValves.put((0, self))
|
|
|
|
|
|
|
|
distanceMap[(self.name, self.name)] = 0
|
|
|
|
|
|
|
|
while not nextValves.empty():
|
|
|
|
curDist, valve = nextValves.get()
|
|
|
|
|
|
|
|
for tunnel in valve.tunnels:
|
|
|
|
if (self.name, tunnel) in distanceMap:
|
|
|
|
continue
|
|
|
|
|
|
|
|
nextValve = valves[tunnel]
|
|
|
|
nextDist = curDist + 1
|
|
|
|
|
|
|
|
distanceMap[(self.name, nextValve.name)] = nextDist
|
|
|
|
nextValves.put((nextDist, nextValve))
|
|
|
|
|
|
|
|
def __lt__(self, other):
|
|
|
|
return self.flowRate < other.flowRate and self.name < other.name
|
|
|
|
|
|
|
|
|
|
|
|
def maxRemaining(remainingTime1, remainingTime2, pos1, pos2, possibleValves):
|
|
|
|
|
|
|
|
volves = possibleValves.copy()
|
|
|
|
possibleRemaining = 0
|
|
|
|
done = False
|
|
|
|
newpos = pos1
|
|
|
|
besttime = remainingTime1
|
|
|
|
|
|
|
|
while not done:
|
|
|
|
best = 0
|
|
|
|
done = True
|
|
|
|
for valve in volves:
|
|
|
|
if remainingTime1 - distanceMap[pos1, valve] - 1 > 0:
|
|
|
|
press = (remainingTime1 - distanceMap[pos1, valve] - 1) * possibleValves[valve]
|
|
|
|
if press > best:
|
|
|
|
done = False
|
|
|
|
best = press
|
|
|
|
newpos = valve
|
|
|
|
besttime = remainingTime1 - distanceMap[pos1, valve] - 1
|
|
|
|
if not done:
|
|
|
|
volves.pop(newpos)
|
|
|
|
possibleRemaining += best
|
|
|
|
remainingTime1 = besttime
|
|
|
|
pos1 = newpos
|
|
|
|
done = False
|
|
|
|
besttime = remainingTime2
|
|
|
|
while not done:
|
|
|
|
best = 0
|
|
|
|
done = True
|
|
|
|
for valve in volves:
|
|
|
|
if remainingTime2 - distanceMap[pos2, valve] - 1 > 0:
|
|
|
|
press = (remainingTime2 - distanceMap[pos2, valve] - 1) * possibleValves[valve]
|
|
|
|
if press > best:
|
|
|
|
done = False
|
|
|
|
best = press
|
|
|
|
newpos = valve
|
|
|
|
besttime = remainingTime2 - distanceMap[pos2, valve] - 1
|
|
|
|
if not done:
|
|
|
|
volves.pop(newpos)
|
|
|
|
possibleRemaining += best
|
|
|
|
remainingTime1 = besttime
|
|
|
|
pos2 = newpos
|
|
|
|
|
|
|
|
# nextSteps = [2 * x for x in range(int(remainingTime / 2) + 1)]
|
|
|
|
|
|
|
|
# allValveValues = list(reversed([v for _, v in possibleValves.items()]))
|
|
|
|
# possibleRemaining = 0
|
|
|
|
|
|
|
|
# for timeOffset in nextSteps:
|
|
|
|
# if timeOffset > remainingTime:
|
|
|
|
# break
|
|
|
|
|
|
|
|
# if len(allValveValues) == 0:
|
|
|
|
# break
|
|
|
|
|
|
|
|
# openFor = remainingTime - timeOffset
|
|
|
|
# possibleRemaining += allValveValues[0] * (remainingTime - timeOffset)
|
|
|
|
# allValveValues = allValveValues[1:]
|
|
|
|
|
|
|
|
# if len(allValveValues) == 0:
|
|
|
|
# break
|
|
|
|
|
|
|
|
# possibleRemaining += allValveValues[0] * (remainingTime - timeOffset)
|
|
|
|
# allValveValues = allValveValues[1:]
|
|
|
|
|
|
|
|
return possibleRemaining
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def step(position1, position2, busy1, busy2, currentTime, pressure, _valvesCons):
|
|
|
|
global curentbest
|
|
|
|
global numTotalSteps
|
|
|
|
global maxRemaining
|
|
|
|
|
|
|
|
numTotalSteps += 1
|
|
|
|
|
|
|
|
if maxRemaining(MAX_STEPS - currentTime - busy1,MAX_STEPS - currentTime - busy2, position1, position2, _valvesCons) + pressure < curentbest:
|
|
|
|
# There's no way we can get better than the current max pressure, so bail.
|
|
|
|
eliminated.setdefault('maxRemaining', 0)
|
|
|
|
eliminated['maxRemaining'] += 1
|
|
|
|
return
|
|
|
|
|
|
|
|
done = False
|
|
|
|
if pressure > curentbest:
|
|
|
|
curentbest = pressure
|
|
|
|
if len(_valvesCons) == 0:
|
|
|
|
return
|
|
|
|
if busy1 == 0:
|
|
|
|
for destination in _valvesCons:
|
|
|
|
_CopyCons = _valvesCons.copy()
|
|
|
|
_dist = distanceMap[(position1, destination)]
|
|
|
|
if (currentTime + _dist + 1) >= MAX_STEPS:
|
|
|
|
continue
|
|
|
|
_busy1 = _dist + 1
|
|
|
|
_pressure = pressure + ((MAX_STEPS - currentTime - _busy1) * _CopyCons[destination])
|
|
|
|
_CopyCons.pop(destination)
|
|
|
|
done = True
|
|
|
|
q.put((_pressure * -1, destination, position2, _busy1, busy2, currentTime, _CopyCons))
|
|
|
|
if done:
|
|
|
|
return
|
|
|
|
if busy2 == 0:
|
|
|
|
for destination in _valvesCons:
|
|
|
|
_CopyCons = _valvesCons.copy()
|
|
|
|
_dist = distanceMap[(position2, destination)]
|
|
|
|
if (currentTime + _dist + 1) >= MAX_STEPS:
|
|
|
|
continue
|
|
|
|
_busy2 =_dist + 1
|
|
|
|
_pressure = pressure + ((MAX_STEPS - currentTime - _busy2)* _CopyCons[destination])
|
|
|
|
_CopyCons.pop(destination)
|
|
|
|
done = True
|
|
|
|
q.put((_pressure * -1, position1, destination, busy1, _busy2, currentTime, _CopyCons))
|
|
|
|
if done:
|
|
|
|
return
|
|
|
|
if busy1 <= 0 and busy2 <= 0:
|
|
|
|
return
|
|
|
|
elif busy2 == 0:
|
|
|
|
idle = busy1
|
|
|
|
elif busy1 == 0:
|
|
|
|
idle = busy2
|
|
|
|
else:
|
|
|
|
idle = min(busy1, busy2)
|
|
|
|
_currentTime = currentTime + idle
|
|
|
|
_busy1 = busy1 - idle
|
|
|
|
_busy2 = busy2 - idle
|
|
|
|
_CopyCons = _valvesCons.copy()
|
|
|
|
if _currentTime >= MAX_STEPS:
|
|
|
|
return
|
|
|
|
q.put((pressure * -1, position1, position2, _busy1, _busy2, _currentTime, _CopyCons))
|
|
|
|
|
|
|
|
|
|
|
|
openvalves = []
|
|
|
|
|
|
|
|
|
|
|
|
with open('input16.txt','r') as f:
|
|
|
|
inp = f.read().splitlines(keepends=False)
|
|
|
|
|
|
|
|
for line in inp:
|
|
|
|
tempA, tempB = line.split(' has flow rate=')
|
|
|
|
_valve = tempA[-2:]
|
|
|
|
tempB = tempB.replace('; tunnel leads to valve ','; tunnels lead to valves ')
|
|
|
|
flowRate, tempA = tempB.split('; tunnels lead to valves ')
|
|
|
|
flowRate = int(flowRate)
|
|
|
|
tunnels = tempA.split(', ')
|
|
|
|
if flowRate == 0:
|
|
|
|
openvalves.append(_valve)
|
|
|
|
else:
|
|
|
|
valvesConsider[_valve] = flowRate
|
|
|
|
newValve = Valve( flowRate, tunnels, _valve)
|
|
|
|
valves[_valve] = newValve
|
|
|
|
|
|
|
|
for _, valve in valves.items():
|
|
|
|
valve.genDistanceMap()
|
|
|
|
|
|
|
|
for i in distanceMap:
|
|
|
|
print(i, distanceMap[i])
|
|
|
|
|
|
|
|
position = 'AA'
|
|
|
|
currentTime = 0
|
|
|
|
pressure = 0
|
|
|
|
curentbest = 0
|
|
|
|
q.put((pressure, position, position, 0, 0, currentTime, valvesConsider))
|
|
|
|
|
|
|
|
while not q.empty():
|
|
|
|
#print(q.qsize())
|
|
|
|
pressure, position1, position2, busy1, busy2, currentTime, _valvesConsider = q.get()
|
|
|
|
# print(q.qsize(), pressure, position1, position2, busy1, busy2, currentTime, numTotalSteps, eliminated)
|
|
|
|
step(position1, position2, busy1, busy2, currentTime, pressure * -1, _valvesConsider)
|
|
|
|
|
|
|
|
|
|
|
|
print(curentbest)
|