2022-12-07 - No Space Left On Device
(original .ipynb)
Day 7 puzzle input is a sequence of characters (mine is here). Part 1 involves reconstructing a file system hierarchy from the output of cd and ls commands, and finding the sum of all folder sizes under 100_000. Part 2 involves using this reconstructed file-system hierarchy to find which is the smallest folder to delete that allows our 70_000_000 (byte? megabyte?) filesystem to have at least 30_000_000 bytes/megabytes/units/sectors/whatever free.
puzzle_input_str = open("./puzzle_input/day7.txt").read()
test_input_str = """$ 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"""
def parse_input(input_str):
command, args = "", []
output = []
for line in input_str.splitlines():
tokens = line.split(" ")
if tokens[0] == "$":
yield (command, args, output)
command, args = tokens[1], tokens[2:]
output = []
else:
output.append(tokens)
yield (command, args, output)
def interpret_command(cwd, command, args, output):
if command == "cd":
return cwd[args[0]]
elif command == "ls":
for info, name in output:
if info == "dir":
if not (name in cwd):
cwd[name] = {"..": cwd}
else:
cwd[name] = int(info)
return cwd
def calculate_size(cwd, path, sizes):
local_total = 0
for name in cwd:
if name == "..":
continue
entry = cwd[name]
if type(entry) == dict:
size = calculate_size(entry, path + name + "/", sizes)
local_total += size
sizes[path + name] = size
elif type(entry) == int:
local_total += entry
return local_total
def find_folder_sizes(input_str):
root = {"/": {}}
cwd = root
shell_history = list(parse_input(input_str))
for command, args, output in shell_history[1:]:
cwd = interpret_command(cwd, command, args, output)
sizes = {}
total = calculate_size(root["/"], "/", sizes)
return (sizes, total)
def part_one(input_str):
max_size = 100_000
(sizes, total) = find_folder_sizes(input_str)
return sum(sizes[name] for name in sizes if sizes[name] < max_size)
assert 95437 == part_one(test_input_str)
print("part one:", part_one(puzzle_input_str))
part one: 1723892
def part_two(input_str):
max_size = 100_000
(sizes, total) = find_folder_sizes(input_str)
free_size = 70_000_000 - total
return min(size for size in sizes.values() if free_size + size >= 30_000_000)
assert part_two(test_input_str) == 24933642
print("part two:", part_two(puzzle_input_str))
part two: 8474158