""" 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])