diff --git a/day7/common.py b/day7/common.py new file mode 100644 index 0000000..eeaa499 --- /dev/null +++ b/day7/common.py @@ -0,0 +1,71 @@ +from __future__ import annotations + +import re +from dataclasses import dataclass + + +@dataclass +class File: + name: str + size: int + + def __equals__(self, other): + return self.name == other.name and self.size == other.size + + +@dataclass +class Folder: + name: str + parent: Folder | None + children: list[Folder | File] + + def __equals__(self, other): + return self.name == other.name and self.parent == other.parent + + @property + def full_name(self): + if self.parent is None: + return "/" + else: + return self.parent.full_name + f"/{self.name}" + + @property + def size(self): + return sum(map(lambda x: x.size, self.children)) + + def __lt__(self, other): + return self.size < other.size + + +def pretty_print(folder: Folder, depth: int = 0) -> None: + print("".join([" " for i in range(depth + 1)]), end="- ") + print(f"{folder.name} (dir)") + for object in folder.children: + if type(object) is Folder: + pretty_print(object, depth + 1) + else: + print("".join([" " for i in range(depth + 2)]), end="- ") + print(f"{object.name} (file, size={object.size})") + + +def parse(filename: str) -> Folder: + filesystem = Folder(name="/", parent=None, children=[]) + with open(filename) as f: + f.readline() + current = filesystem + while line := f.readline()[:-1]: + if line[0] == "$": + if match := re.match(r"\$ cd (.+)", line): + folder_name = match.group(1) + if folder_name != "..": + current = filter(lambda x: x.name == folder_name, current.children).__next__() + else: + current = current.parent + else: + if match := re.match(r"(\d+) ((?:\w|.)+)", line): + fichier = File(name=match.group(2), size=int(match.group(1))) + current.children.append(fichier) + elif match := re.match(r"dir (\w+)", line): + folder = Folder(name=match.group(1), parent=current, children=[]) + current.children.append(folder) + return filesystem diff --git a/day7/part1.py b/day7/part1.py new file mode 100755 index 0000000..4cedb80 --- /dev/null +++ b/day7/part1.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python +from common import Folder, parse + + +def solve(folder: Folder) -> int: + childrens_sizes = sum(map(lambda x: solve(x), filter(lambda y: type(y) is Folder, folder.children))) + if folder.size >= 100000: + return childrens_sizes + else: + return folder.size + childrens_sizes + + +def main(): + print(solve(parse("input"))) + + +if __name__ == "__main__": + main() diff --git a/day7/part2.py b/day7/part2.py new file mode 100755 index 0000000..4c788ce --- /dev/null +++ b/day7/part2.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python +from common import Folder, parse + + +def folders_big_enough(folder: Folder, threshold: int) -> list[Folder]: + if folder.size < threshold: + return [] + else: + folder_list = [folder] + for child in filter(lambda x: type(x) is Folder, folder.children): + folder_list += folders_big_enough(child, threshold) + return folder_list + + +def solve(folder: Folder) -> int: + threshold = 30000000 - (70000000 - folder.size) + return min(sorted(folders_big_enough(folder, threshold))).size + + +def main(): + print(solve(parse("input"))) + + +if __name__ == "__main__": + main() diff --git a/day7/toy_input b/day7/toy_input new file mode 100644 index 0000000..09a921e --- /dev/null +++ b/day7/toy_input @@ -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 diff --git a/day8/common.py b/day8/common.py new file mode 100644 index 0000000..8f8acfd --- /dev/null +++ b/day8/common.py @@ -0,0 +1,3 @@ +def parse(filename: str) -> list[list[int]]: + with open(filename) as f: + return [[int(i) for i in line.strip("\n")] for line in f.readlines()] diff --git a/day8/part1.py b/day8/part1.py new file mode 100755 index 0000000..696bb0e --- /dev/null +++ b/day8/part1.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python +from common import parse + + +def is_visible(forest: list[list[int]], x: int, y: int) -> bool: + height = forest[y][x] + west = forest[y][0:x] + east = forest[y][x + 1 :] + north = [forest[i][x] for i in range(y)] + south = [forest[i][x] for i in range(y + 1, len(forest))] + return any(map(lambda x: x == [] or max(x) < height, (west, east, north, south))) + + +def solve(input: list[list[int]]) -> int: + count = 0 + for y, line in enumerate(input): + for x, tree in enumerate(line): + count += 1 if is_visible(input, x, y) else 0 + return count + + +def main(): + print(solve(parse("input"))) + + +if __name__ == "__main__": + main() diff --git a/day8/part2.py b/day8/part2.py new file mode 100755 index 0000000..6ed2a07 --- /dev/null +++ b/day8/part2.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python +from common import parse + + +def scenic_score(forest: list[list[int]], x: int, y: int) -> int: + height = forest[y][x] + sw = se = sn = ss = 0 + west = reversed(forest[y][0:x]) + for w in west: + if w < height: + sw += 1 + continue + elif w == height: + sw += 1 + break + east = forest[y][x + 1 :] + for e in east: + if e < height: + se += 1 + continue + elif e == height: + se += 1 + break + north = reversed([forest[i][x] for i in range(y)]) + for n in north: + if n < height: + sn += 1 + continue + elif n == height: + sn += 1 + break + south = [forest[i][x] for i in range(y + 1, len(forest))] + for s in south: + if s < height: + ss += 1 + continue + elif s == height: + ss += 1 + break + + return sw * se * sn * ss + + +def solve(input: list[list[int]]) -> int: + maxi = 0 + for y, line in enumerate(input): + for x, tree in enumerate(input): + maxi = max(maxi, scenic_score(input, x, y)) + return maxi + + +def main(): + print(solve(parse("input"))) + + +if __name__ == "__main__": + main() diff --git a/day8/toy_input b/day8/toy_input new file mode 100644 index 0000000..6557024 --- /dev/null +++ b/day8/toy_input @@ -0,0 +1,5 @@ +30373 +25512 +65332 +33549 +35390 \ No newline at end of file