mirror of
https://github.com/cupcakearmy/advent-of-code.git
synced 2024-12-21 15:46:28 +00:00
07
This commit is contained in:
parent
bf613c4583
commit
720c9924da
11
2022/07/README.md
Normal file
11
2022/07/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
# 07
|
||||
|
||||
Loved this one too!! Writing a littler shell "emulator" was def. fun! Also caching directory sizes for performance :)
|
||||
|
||||
<details>
|
||||
<summary>Solutions</summary>
|
||||
<ol>
|
||||
<li>1306611</li>
|
||||
<li>13210366</li>
|
||||
</ol>
|
||||
</details>
|
115
2022/07/python/main.py
Normal file
115
2022/07/python/main.py
Normal file
@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from dataclasses import dataclass
|
||||
from os.path import dirname, join
|
||||
from typing import Callable, ClassVar, Literal, Union
|
||||
|
||||
# Day 07
|
||||
|
||||
# Common
|
||||
|
||||
|
||||
def read_input(filename):
|
||||
data = join(dirname(__file__), '..', filename)
|
||||
with open(data) as f:
|
||||
return f.read().strip()
|
||||
|
||||
|
||||
test = read_input('test.txt')
|
||||
data = read_input('input.txt')
|
||||
|
||||
|
||||
@dataclass
|
||||
class File:
|
||||
size: int
|
||||
|
||||
|
||||
@dataclass
|
||||
class Directory:
|
||||
name: str
|
||||
contents: dict[str, Union['Directory', File]]
|
||||
parent: Union[None, 'Directory'] = None
|
||||
_size: int | None = None
|
||||
|
||||
def size(self) -> int:
|
||||
if self._size is None:
|
||||
self._size = sum([
|
||||
entry.size if isinstance(entry, File) else entry.size()
|
||||
for entry in self.contents.values()
|
||||
])
|
||||
return self._size
|
||||
|
||||
def walk(self, fn: Callable[[Union[File, 'Directory']], None]):
|
||||
for entry in self.contents.values():
|
||||
fn(entry)
|
||||
if isinstance(entry, Directory):
|
||||
entry.walk(fn)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Command:
|
||||
command: str
|
||||
output: list[str]
|
||||
|
||||
|
||||
@dataclass
|
||||
class Shell:
|
||||
commands: list[Command]
|
||||
root: Directory
|
||||
cwd: Directory
|
||||
|
||||
def execute(self):
|
||||
for command in self.commands:
|
||||
cmd, *args = command.command.split()
|
||||
match cmd:
|
||||
case 'ls':
|
||||
for entry in command.output:
|
||||
size, name = entry.split()
|
||||
self.cwd.contents[name] = Directory(name, {}, self.cwd) if size == 'dir' else File(int(size))
|
||||
case 'cd':
|
||||
match args[0]:
|
||||
case '/':
|
||||
self.cwd = self.root
|
||||
case '..':
|
||||
self.cwd = self.cwd.parent
|
||||
case _:
|
||||
self.cwd = self.cwd.contents[args[0]]
|
||||
|
||||
def get_all_sizes(self) -> list[int]:
|
||||
sizes: list[int] = []
|
||||
|
||||
def fn(entry: Directory | File):
|
||||
if isinstance(entry, Directory):
|
||||
sizes.append(entry.size())
|
||||
self.root.walk(fn)
|
||||
return sizes
|
||||
|
||||
def flag_1(self):
|
||||
directories = self.get_all_sizes()
|
||||
return sum([size for size in directories if size <= 100_000])
|
||||
|
||||
def flag_2(self, total=70_000_000, needed=30_000_000):
|
||||
to_remove = needed - total + self.root.size()
|
||||
big_enough = sorted([
|
||||
size
|
||||
for size in self.get_all_sizes()
|
||||
if size > to_remove
|
||||
])
|
||||
return big_enough[0]
|
||||
|
||||
@staticmethod
|
||||
def parse(data: str):
|
||||
commands = [command.strip().split('\n') for command in data.split('$ ')[1:]]
|
||||
root = Directory('/', {})
|
||||
return Shell([Command(command[0], command[1:]) for command in commands], root, root)
|
||||
|
||||
|
||||
shell = Shell.parse(test)
|
||||
shell.execute()
|
||||
print(shell.flag_1())
|
||||
print(shell.flag_2())
|
||||
|
||||
shell = Shell.parse(data)
|
||||
shell.execute()
|
||||
print(shell.flag_1())
|
||||
print(shell.flag_2())
|
Loading…
Reference in New Issue
Block a user