★Advent of Code 202225 days solved.Source ↗
Day 7 · finished October 2026

No Space Left On Device

“higher-order function <==> function that takes functions as input”day-7.py
from helpers import load_data
from tree import TreeNode

# extend generic tree to store files on each node
class DirNode(TreeNode):
	def __init__(self, name, parent):
		super().__init__(name, parent)
		# application specific property
		self.files = {}
	
	# TODO this should be in the base class somehow, using Python's
	# TODO equivalent to generics
	def add_child(self, name):
		if self.has_child_with_name(name):
			return self.get_child_by_name(name)
		else:
			new_node = DirNode(name, self)
			self.children.append(new_node)
		return new_node


	# cannot use generic print because we want an application-specific property
	def print_dir(self, depth = 0):
		print(' ' * depth + '- ' + self.name + ' (dir)')
		for k, v in self.files.items():
			print(' ' * (depth + 1) + '- ' + k + ' (file, size=' + str(v) + ')')
		for child in self.children:
			child.print_dir(depth + 1)

	# example use case of the traversing higher-order function
	# higher-order function <==> function that takes functions as input
	def dir_size(self):
		def sum_files(node):
			return sum([v for v in node.files.values()])
		return self.traverse_accumulate(sum_files)


# [(dir, size), ..., (dir, size)] where size >= threshold
def get_deletion_candidates(node, min_delete_threshold):
	temp_list = []
	size = node.dir_size()
	if size >= min_delete_threshold:
		temp_list.append((node.name, size))
	for child in node.children:
		temp_list.extend(get_deletion_candidates(child, min_delete_threshold))
	return temp_list

if __name__ == "__main__":
	data = load_data("day-7-input.txt")

	previous_node = None
	current_node = DirNode('/', None)
	for line in data[1:]:
		# switch dir command
		if line.startswith('$ cd '):
			previous_node = current_node
			temp = line.replace('$ cd ', '')
			current_node = current_node.parent if temp == '..' else current_node.add_child(temp)
		# dir listed
		elif line.startswith('dir'):
			_, name = line.split(' ')
			current_node.add_child(name)
		# file size listed
		elif line[0].isnumeric():
			size, name = line.split(' ')
			current_node.files[name] = int(size)

	# seek to root node
	root_node = current_node
	while root_node.parent != None:
		root_node = root_node.parent

	# show our nice file structure
	root_node.print_dir()

	# part 1
	def sum_if_100_000(node):
		temp_sum = node.dir_size() 
		return temp_sum if temp_sum <= 100_000 else 0
	print(root_node.traverse_accumulate(sum_if_100_000))

	# part 2
	need_to_free = 30_000_000 - (70_000_000 - root_node.dir_size())
	ans = get_deletion_candidates(root_node, need_to_free)
	ans.sort(key = lambda x: x[1])
	print(ans[0][1])

    # part 1 solution: 1490523
    # part 2 solution: 12390492

No writeup for this day yet.