~aperezdc/aoc2022

40ee8aaf555b1e2f35fe17e444707927b853210d — Adrian Perez de Castro 2 years ago ce7b15e
Day 7, first part
2 files changed, 112 insertions(+), 0 deletions(-)

A day07/day07.py
A day07/day07.test
A day07/day07.py => day07/day07.py +89 -0
@@ 0,0 1,89 @@
#! /usr/bin/env python3
# vim:fenc=utf-8
#
# Copyright © 2022 Adrian Perez de Castro <aperez@igalia.com>
#
# Distributed under terms of the MIT license.

from dataclasses import dataclass, field
from pathlib import PosixPath as Path

@dataclass
class Entry:
    name: str

@dataclass
class File(Entry):
    size: int

@dataclass
class Directory(Entry):
    entries: list[Entry] = field(default_factory=list)

    def walk(self, p: Path):
        return self.__walk(p.parts)

    def __walk(self, p: tuple[str]):
        if len(p) == 0:
            return self
        elif p[0] == "/":
            return top.__walk(p[1:])
        else:
            for item in self.entries:
                if item.name == p[0]:
                    if len(p) == 1:
                        return item
                    else:
                        assert isinstance(item, Directory)
                        return item.__walk(p[1:])
            raise KeyError(p[0])

    @property
    def size(self):
        return sum(item.size for item in self.entries)

    def find(self, predicate):
        if predicate(self):
            yield self
        for item in self.entries:
            if isinstance(item, Directory):
                yield from item.find(predicate)


pwd = Path("/")
top = Directory(name="/")
cur = top

import sys

for line in sys.stdin.readlines():
    items = line.strip().split()
    assert len(items) >= 2
    if items[0] == "$":
        if items[1] == "cd":
            assert len(items) == 3
            if items[2] == "/":
                pwd = Path("/")
            elif items[2] == "..":
                pwd = pwd.parent
            else:
                pwd = pwd / items[2]
        elif items[1] == "ls":
            assert len(items) == 2
            cur = top.walk(pwd)
        else:
            assert False, "Unreachable"
    else:
        assert len(items) == 2
        if items[0] == "dir":
            cur.entries.append(Directory(items[1]))
        else:
            cur.entries.append(File(items[1], int(items[0])))

if len(sys.argv) > 1:
    for item in sys.argv[1:]:
        print(top.walk(Path(item)).size)
    raise SystemExit

# Find all directories with a size at most 100000
print(sum(item.size for item in top.find(lambda item: item.size <= 100000)))

A day07/day07.test => day07/day07.test +23 -0
@@ 0,0 1,23 @@
$ 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