adventOfCode/2023/5/part2.py
2023-12-05 13:02:56 +01:00

82 lines
2.8 KiB
Python

previous: list[range] = []
current: list[range] = []
def finishmap():
global previous
global current
print(current, previous)
current += previous
previous = current
current = []
previous = mergeRanges(previous)
def mergeRanges(ranges: list[range]) -> list[range]:
ranges.sort(key=lambda x: x.start)
newRanges: list[range] = []
for i in ranges:
if len(newRanges) == 0:
newRanges.append(i)
continue
if not overlap(newRanges[-1], i):
newRanges.append(i)
continue
newRanges[-1] = range(min(newRanges[-1].start, i.start), max(newRanges[-1].stop, i.stop))
newRanges.append(i)
return newRanges
def overlap(range1: range, range2: range):
if range1.start >= range2.stop or range1.stop <= range2.start:
return False
return True
def getOverlapRange(range1: range, range2: range) -> tuple[range|None,range,range|None]:
if not overlap(range1, range2):
raise Exception("Ranges do not overlap")
return (
range(range1.start, range2.start) if range1.start < range2.start else None,
range(max(range1.start, range2.start), min(range1.stop, range2.stop)),
range(range2.stop, range1.stop) if range1.stop > range2.stop else None
)
def splitRange(range1: range, at: int) -> tuple[range,range]:
if not at in range1:
raise Exception("at not in range")
return (range(range1.start, at), range(at, range1.stop))
for line in open("input2"):
if line.startswith("seeds:"):
split = line.split()[1:]
previous = [range(int(x), int(x) + int(y)) for x, y in zip(split[::2], split[1::2])]
continue
if line.endswith("map:\n"):
print(line[:-5])
finishmap()
continue
if len(line.split()) < 3: continue
dest, source, length = line.split()
dest = int(dest)
source = int(source)
offset = dest - source
length = int(length)
sourceRange = range(source, source + length)
maxloops = 10
toRemove: list[range] = []
newPrevious: list[range] = []
for i in previous:
if not overlap(i, sourceRange): continue
toRemove.append(i)
if i.start == sourceRange.start and i.stop == sourceRange.stop:
current.append(range(dest, dest + length))
continue
nonoverlap1, overlapping, nonoverlap2 = getOverlapRange(i, sourceRange)
if nonoverlap1 is not None and nonoverlap1.start < nonoverlap1.stop:
newPrevious.append(nonoverlap1)
current.append(range(overlapping.start + offset, overlapping.stop + offset))
if nonoverlap2 is not None and nonoverlap2.start < nonoverlap2.stop:
newPrevious.append(nonoverlap2)
for i in toRemove:
previous.remove(i)
previous += newPrevious
finishmap()
print(min(prev.start for prev in previous))