d8: add data

master
pegasust 2022-12-08 05:01:20 +00:00
parent b2602f9666
commit 0547d489ba
3 changed files with 109 additions and 1119 deletions

View File

@ -1,23 +1,5 @@
$ 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
30373
25512
65332
33549
35390

File diff suppressed because it is too large Load Diff

View File

@ -1,123 +1,10 @@
#!/usr/bin/env python3
from typing import Iterable, Optional
from dataclasses import dataclass
from functools import reduce
@dataclass
class File:
name: str
is_dir: bool
children: dict[str, "File"]
parent: Optional["File"]
size: Optional[int]
class Main:
def __init__(self, lines: Iterable[str]):
self.root = File("/",True, {}, None, None)
self.cwd = self.root
self.lines = lines
def handle_cmd(self, cmdlets: list[str]):
match cmdlets[0]:
case "cd":
dest = cmdlets[1]
match dest:
case "/":
self.cwd = self.root
case "..":
if not self.cwd.parent:
return self
self.cwd = self.cwd.parent
case _:
self.cwd = self.cwd.children[dest]
# validate cwd
return self
case "ls":
return self
case _:
raise RuntimeError(f"Unknown command: {cmdlets[0]}")
def parse(self):
for _line in self.lines:
line = _line.strip()
if len(line) == 0:
continue
# print("line:", line)
if line[0] == "$": # command
cmdlets = line[1:].split()
self.handle_cmd(cmdlets)
continue
# it's just ls listing, update it to our object storage
(sz, rel_path) = line.split()
self.cwd.children[rel_path] = File(name=rel_path,
is_dir=sz == "dir",
children={},
parent=self.cwd,
size=int(sz) if sz != "dir" else None)
return self
def solve(self):
self.parse()
def sized(file: File, parent: Optional[File]):
"""
alternative file
"""
if file.size:
return file
retval = File(file.name, file.is_dir, {}, None, None)
children = {rel_path: sized(f, retval) for rel_path, f in file.children.items()}
retval.children = children
retval.parent = parent
retval.size = sum(c.size for c in children.values())
return retval
def sum_with_threshold(sized_file: File, max_sz: int) -> int:
assert sized_file.size is not None
sz = 0
if sized_file.size <= max_sz and len(sized_file.children) != 0:
# print("qual:", sized_file.name)
sz = sized_file.size
return sum(sum_with_threshold(c, max_sz) for c in sized_file.children.values()) + sz
sized_root = sized(self.root, None)
part1 = sum_with_threshold(sized_root, 100_000)
print("part1", part1)
def directories(file: File) -> list[File]:
if not file.is_dir:
return []
return [file] + [dir for f in file.children.values() for dir in directories(f)]
def upper_bound(sized_file: File, min_sz: int) -> list[File]:
assert sized_file.size is not None
if sized_file.size < min_sz or len(sized_file.children) == 0:
return []
min_f: File = sized_file
contests = [c for e in sized_file.children.values() for c in upper_bound(e, min_sz)]
return [min_f] + contests
TOTAL=70_000_000
NEED=30_000_000
assert sized_root.size is not None
DELETE=NEED-(TOTAL-sized_root.size)
print(f"{DELETE=}")
part2 = upper_bound(sized_root, DELETE)
p = sorted(part2, key=lambda x: x.size or 0)
# print("part2 qual:", "\n".join([f"({e.name}, {e.size})" for e in p]))
print("part2", p[0].size if part2 else "None")
sorted_dirs = sorted(directories(sized_root), key=lambda x: x.size or 0)
# Before is_dir: 176 for part 2
print(f"directories ({len(sorted_dirs)}):")
print("\n".join(f"{dir.name}\t{dir.size}" for dir in sorted_dirs))
import sys
from typing import Iterable
def main(lines: Iterable[str]):
Main(list(lines)).solve()
pass
if __name__=="__main__":
import sys
with open(sys.argv[1], "r") as f:
main(f)