advent-of-code/2022/7/7.py
2022-12-07 14:52:52 +01:00

119 lines
2.6 KiB
Python

"""
parse commandline output, reconstruct a filesystem and determine the sum of all folders < 100kB
"""
TESTRUN = True
test_text = """$ cd /
$ ls
dir a
14848514 b.txt
8504156 c.dat
dir d
$ cd a
$ ls
dir e
29116 f
2557 g
62596 h.lst
$ cd e
$ ls
584 i
$ cd ..
$ cd ..
$ cd d
$ ls
4060174 j
8033020 d.log
5626152 d.ext
7214296 k
"""
with open('2022/7/stdout.txt') as filein:
input_text = filein.read()
text = test_text if TESTRUN else input_text
def parse_stdin(stdin: str):
outputs = stdin.split('$')
outputs = [[line.strip() for line in output.splitlines()] for output in outputs if output]
return recursive_parse(outputs)
def recursive_parse(outputs: list):
structure = {}
while True:
try:
current = outputs.pop(0)
except IndexError:
return structure
command = current.pop(0)
if command.startswith('ls'):
content = [c.split() for c in current]
for value, name in content:
structure[name] = int(value) if value.isnumeric() else value
elif command.startswith('cd'):
destination = command.split()[1]
if destination == '..':
return structure
else:
structure[destination] = recursive_parse(outputs)
def recursive_sum(d: dict, folders: list = None, initial=True):
s = 0
folders = [] if folders is None else folders
for name, value in d.items():
if isinstance(value, dict):
zs = recursive_sum(value, folders, False)
folders.append((name, zs))
else:
zs = value
s += zs
if initial:
return folders
else:
return s
def folders_up_to_size(folders: list, size: int):
return [(k, v) for k, v in folders if v <= size]
def recursive_print(d: dict, indent=0, increment=2):
for k, v in d.items():
if isinstance(v, dict):
print(' '*indent, 'dir', k)
recursive_print(v, indent+increment)
else:
print(' '*indent, k, v)
system = parse_stdin(text)
# recursive_print(system)
sums = recursive_sum(system)
summed_folders = folders_up_to_size(sums, 100000)
print(summed_folders)
print(sum([v for _, v in summed_folders]))
"""
now find the smallest folder that can be deleted to free up the space needed to keep the total size under 40MB
"""
def folders_over_size(folders: list, size: int):
return [(k, v) for k, v in folders if v > size]
total = sums[-1][1]
over = total-40000000
print('filesystem overfull by:', over)
summed_folders = folders_over_size(sums, over)
summed_folders.sort(key=lambda x: x[1])
print(summed_folders[0])