diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 99856e3..4a62cd4 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,3 +1,3 @@ -FROM mcr.microsoft.com/devcontainers/python:1-3.12-bullseye +FROM mcr.microsoft.com/devcontainers/python:1-3.13-bullseye COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin/ diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 0e50fd4..395d8c5 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -10,7 +10,8 @@ }, "containerEnv": { "UV_CACHE_DIR": "${containerWorkspaceFolder}/.uv/cache", - "UV_TOOL_DIR": "${containerWorkspaceFolder}/.uv/tools" + "UV_TOOL_DIR": "${containerWorkspaceFolder}/.uv/tools", + "PYTHON_HISTORY": "${containerWorkspaceFolder}/.python_history" }, "updateContentCommand": "uv sync && uv run poe sync", "portsAttributes": { diff --git a/.github/actions/uv-project-setup/action.yaml b/.github/actions/uv-project-setup/action.yaml index 7737099..7d1102e 100644 --- a/.github/actions/uv-project-setup/action.yaml +++ b/.github/actions/uv-project-setup/action.yaml @@ -11,7 +11,7 @@ runs: - name: Setup python uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5 with: - python-version: 3.12 + python-version: 3.13 - name: Install project dependencies run: uv sync shell: bash diff --git a/.gitignore b/.gitignore index ee6ced5..1c99135 100644 --- a/.gitignore +++ b/.gitignore @@ -166,3 +166,4 @@ cython_debug/ /node_modules/ /.ruff_cache/ +/.python_history diff --git a/adventofcode/main.py b/adventofcode/main.py index 421907b..4fd9ea8 100644 --- a/adventofcode/main.py +++ b/adventofcode/main.py @@ -6,7 +6,7 @@ import sys import time from enum import StrEnum -from typing import TYPE_CHECKING, Annotated, Any, TypeGuard, assert_never +from typing import TYPE_CHECKING, Annotated, Any, TypeIs, assert_never import joblib import typer @@ -253,7 +253,7 @@ def __init__(self, result_type: type) -> None: super().__init__(f"Invalid result type: {result_type}") -def is_valid_result_type(result: Any) -> TypeGuard[answers.AnswerType]: # noqa: ANN401 +def is_valid_result_type(result: Any) -> TypeIs[answers.AnswerType]: # noqa: ANN401 return isinstance(result, int) diff --git a/adventofcode/tooling/map.py b/adventofcode/tooling/map.py index 6c8929e..1cfa2fc 100644 --- a/adventofcode/tooling/map.py +++ b/adventofcode/tooling/map.py @@ -1,7 +1,7 @@ from __future__ import annotations import enum -from typing import TYPE_CHECKING, Literal, assert_never, overload +from typing import TYPE_CHECKING, Generic, Literal, TypeVar, assert_never, overload from .coordinates import X, Y from .directions import RotationDirection @@ -25,7 +25,10 @@ class IterDirection(enum.Enum): Columns = enum.auto() -class Map2d[Map2dDataType]: +Map2dDataType = TypeVar("Map2dDataType", default=str) + + +class Map2d(Generic[Map2dDataType]): __slots__ = ("_br_x", "_br_y", "_height", "_sequence_data", "_width") def __init__( diff --git a/adventofcode/y2023/d11.py b/adventofcode/y2023/d11.py index 6fd908a..43c255f 100644 --- a/adventofcode/y2023/d11.py +++ b/adventofcode/y2023/d11.py @@ -5,7 +5,7 @@ from adventofcode.tooling.map import Map2d -class _InputMap(Map2d[str]): +class _InputMap(Map2d): def __init__(self, data: Iterable[str]) -> None: super().__init__(list(data)) diff --git a/adventofcode/y2023/d13.py b/adventofcode/y2023/d13.py index f03181a..220b23d 100644 --- a/adventofcode/y2023/d13.py +++ b/adventofcode/y2023/d13.py @@ -6,7 +6,7 @@ from adventofcode.tooling.map import IterDirection, Map2d -def _parse_maps(input_str: str) -> Iterable[Map2d[str]]: +def _parse_maps(input_str: str) -> Iterable[Map2d]: lines: list[list[str]] = [] for line in input_str.splitlines(): if not line: @@ -31,7 +31,7 @@ def _compare_datas( def _find_consecutive_rows_or_columns( - map_: Map2d[str], + map_: Map2d, start_pos: int, direction: IterDirection, allowed_mismatches: int, @@ -59,7 +59,7 @@ def _map_data_iter_to_data(d: tuple[int, str]) -> str: def _check_if_datas_around_reflection_match( - map_: Map2d[str], + map_: Map2d, pos_before_reflection: int, direction: IterDirection, allowed_mismatches: int, @@ -105,7 +105,7 @@ def _check_if_datas_around_reflection_match( def _find_reflection_line( - map_: Map2d[str], direction: IterDirection, required_mismatches: int = 0 + map_: Map2d, direction: IterDirection, required_mismatches: int = 0 ) -> int | None: logging.debug( "Searching for reflection with %d required mismatches", required_mismatches diff --git a/adventofcode/y2023/d14.py b/adventofcode/y2023/d14.py index b4eea7a..ffe65e0 100644 --- a/adventofcode/y2023/d14.py +++ b/adventofcode/y2023/d14.py @@ -9,7 +9,7 @@ _logger = logging.getLogger(__name__) -def _calculate_load(map_: Map2d[str]) -> int: +def _calculate_load(map_: Map2d) -> int: max_load = map_.height return sum( max_load - y @@ -152,7 +152,7 @@ def _get_new_rock_coords( return Coord2d(coord.y, x) -def _roll_rocks(map_: Map2d[str], direction: Dir) -> Map2d[str]: +def _roll_rocks(map_: Map2d, direction: Dir) -> Map2d: lines: list[list[str]] = [["."] * map_.width for _ in range(map_.height)] roller: _RollVertical | _RollHorizontal match direction: @@ -184,13 +184,13 @@ def p1(input_str: str) -> int: return _calculate_load(_roll_rocks(map_, Dir.N)) -def _perform_spin(map_: Map2d[str]) -> Map2d[str]: +def _perform_spin(map_: Map2d) -> Map2d: for dir_ in (Dir.N, Dir.W, Dir.S, Dir.E): map_ = _roll_rocks(map_, dir_) return map_ -def _get_rock_coords(map_: Map2d[str]) -> frozenset[tuple[int, int]]: +def _get_rock_coords(map_: Map2d) -> frozenset[tuple[int, int]]: return frozenset( (x, y) for y, x_iter in map_.iter_data() for x, sym in x_iter if sym == "O" ) @@ -199,9 +199,9 @@ def _get_rock_coords(map_: Map2d[str]) -> frozenset[tuple[int, int]]: def p2(input_str: str) -> int: map_ = Map2d([list(line) for line in input_str.splitlines()]) _logger.debug("Initial map:\n%s", map_) - maps_after_spins: list[Map2d[str]] = [] + maps_after_spins: list[Map2d] = [] seen_rock_coords: dict[frozenset[tuple[int, int]], int] = {} - final_map: Map2d[str] | None = None + final_map: Map2d | None = None for i in range(1, 1_000_000_000 + 1): map_ = _perform_spin(map_) _logger.info("Done spinning %d", i) diff --git a/adventofcode/y2023/d16.py b/adventofcode/y2023/d16.py index b7d1a8a..717a92d 100644 --- a/adventofcode/y2023/d16.py +++ b/adventofcode/y2023/d16.py @@ -32,7 +32,7 @@ def add( def _process_splitter_exit( - coord: Coord2d, dir_: Dir, map_: Map2d[str] + coord: Coord2d, dir_: Dir, map_: Map2d ) -> tuple[set[Coord2d], list[tuple[Coord2d, Dir]]]: visited: set[Coord2d] = set() next_splitter_exits: list[tuple[Coord2d, Dir]] = [] @@ -95,7 +95,7 @@ def _process_splitter_exit( def _try_one_enter( enter_coord: Coord2d, enter_dir: Dir, - map_: Map2d[str], + map_: Map2d, exit_cache: _SplitterExitCache, ) -> int: visited: set[Coord2d] = set() diff --git a/adventofcode/y2023/d19.py b/adventofcode/y2023/d19.py index 531f8c7..c812458 100644 --- a/adventofcode/y2023/d19.py +++ b/adventofcode/y2023/d19.py @@ -5,7 +5,7 @@ from collections.abc import Iterable, Mapping from enum import Enum from queue import Queue -from typing import Literal, NewType, TypeGuard, cast +from typing import Literal, NewType, TypeIs, cast from attrs import define, frozen @@ -18,7 +18,7 @@ _Part = NewType("_Part", Mapping[_Category, int]) -def is_category(category: str) -> TypeGuard[_Category]: +def is_category(category: str) -> TypeIs[_Category]: return category in _categories diff --git a/pyproject.toml b/pyproject.toml index 7067f06..6e7285a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ name = "adventofcode" version = "0.1.0" description = "" readme = "README.md" -requires-python = ">=3.12" +requires-python = ">=3.13" dependencies = [ "attrs ==24.3.0", "typer ==0.15.1", diff --git a/uv.lock b/uv.lock index 965df90..0962327 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -requires-python = ">=3.12" +requires-python = ">=3.13" [[package]] name = "adventofcode" @@ -133,11 +133,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/e8/21/7e9e523537991d145ab8a0a2fd98548d67646dc2aaaf6091c31ad883e7c1/mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e", size = 3152532 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/31/c526a7bd2e5c710ae47717c7a5f53f616db6d9097caf48ad650581e81748/mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5", size = 11077900 }, - { url = "https://files.pythonhosted.org/packages/83/67/b7419c6b503679d10bd26fc67529bc6a1f7a5f220bbb9f292dc10d33352f/mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e", size = 10074818 }, - { url = "https://files.pythonhosted.org/packages/ba/07/37d67048786ae84e6612575e173d713c9a05d0ae495dde1e68d972207d98/mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2", size = 12589275 }, - { url = "https://files.pythonhosted.org/packages/1f/17/b1018c6bb3e9f1ce3956722b3bf91bff86c1cefccca71cec05eae49d6d41/mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0", size = 13037783 }, - { url = "https://files.pythonhosted.org/packages/cb/32/cd540755579e54a88099aee0287086d996f5a24281a673f78a0e14dba150/mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2", size = 9726197 }, { url = "https://files.pythonhosted.org/packages/11/bb/ab4cfdc562cad80418f077d8be9b4491ee4fb257440da951b85cbb0a639e/mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7", size = 11069721 }, { url = "https://files.pythonhosted.org/packages/59/3b/a393b1607cb749ea2c621def5ba8c58308ff05e30d9dbdc7c15028bca111/mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62", size = 10063996 }, { url = "https://files.pythonhosted.org/packages/d1/1f/6b76be289a5a521bb1caedc1f08e76ff17ab59061007f201a8a18cc514d1/mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8", size = 12584043 }, @@ -210,16 +205,6 @@ version = "5.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/3c/14/726f2e2553aca08f25b7166197d22a4426053d5fb423c53417342ac584b1/pyinstrument-5.0.0.tar.gz", hash = "sha256:144f98eb3086667ece461f66324bf1cc1ee0475b399ab3f9ded8449cc76b7c90", size = 262211 } wheels = [ - { url = "https://files.pythonhosted.org/packages/02/ec/fb3a3df90d561d5e0c6682627d2fb3d582af92c311d116633fb83f399ba9/pyinstrument-5.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:dec3529a5351ea160baeef1ef2a6e28b1a7a7b3fb5e9863fae8de6da73d0f69a", size = 128364 }, - { url = "https://files.pythonhosted.org/packages/73/fa/4b079dba81995a968b84ebcea0335dfe6e273b5ec9f079aee5a662e574c1/pyinstrument-5.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5a39e3ef84c56183f8274dfd584b8c2fae4783c6204f880513e70ab2440b9137", size = 120380 }, - { url = "https://files.pythonhosted.org/packages/2b/37/e51aa7a30f622e811d1d771c80f86eefdd98ca0ad7ed8f9d8cdfcdc9572f/pyinstrument-5.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3938f063ee065e05826628dadf1fb32c7d26b22df4a945c22f7fe25ea1ba6a2", size = 143834 }, - { url = "https://files.pythonhosted.org/packages/25/eb/8711a084acb173dc2d5df1034348a99968c1b0f9a4dc4d487d0ec04428ff/pyinstrument-5.0.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f18990cc16b2e23b54738aa2f222863e1d36daaaec8f67b1613ddfa41f5b24db", size = 142765 }, - { url = "https://files.pythonhosted.org/packages/67/a1/30ed993fe10921f25e69f67125685f708178311f531aa3b791c1424db877/pyinstrument-5.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3731412b5bfdcef8014518f145140c69384793e218863a33a39ccfe5fb42045", size = 144121 }, - { url = "https://files.pythonhosted.org/packages/21/35/bb28bde4803713ab2e7da2c9764eab25c6f28a1d52677c19eb159f666a6a/pyinstrument-5.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:02b2eaf38460b14eea646d6bb7f373eb5bb5691d13f788e80bdcb3a4eaa2519e", size = 143816 }, - { url = "https://files.pythonhosted.org/packages/68/dd/3c0bc95901b9b92a8751b45236cff4493ec0f2061827b142cd25e6a08bf2/pyinstrument-5.0.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e57db06590f13657b2bce8c4d9cf8e9e2bd90bb729bcbbe421c531ba67ad7add", size = 143555 }, - { url = "https://files.pythonhosted.org/packages/52/bd/ac2f907152605b18cb7143de4dbbf825e79497273c940277d59e89832982/pyinstrument-5.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ddaa3001c1b798ec9bf1266ef476bbc0834b74d547d531f5ed99e7d05ac5d81b", size = 143989 }, - { url = "https://files.pythonhosted.org/packages/98/dd/07d1a3c9c0abf4518ff3881c0da81f1064383dddb094f56f8c1f78748c8f/pyinstrument-5.0.0-cp312-cp312-win32.whl", hash = "sha256:b69ff982acf5ef2f4e0f32ce9b4b598f256faf88438f233ea3a72f1042707e5b", size = 121974 }, - { url = "https://files.pythonhosted.org/packages/a1/ed/2503309f485bf4c8893b76d585323505f422c5fa1e1885ee9d4a2bb57aa5/pyinstrument-5.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:0bf4ef061d60befe72366ce0ed4c75dee5be089644de38f9936d2df0bcf44af0", size = 122759 }, { url = "https://files.pythonhosted.org/packages/49/c9/b2ed3db062bca45decb7fdcab2ed2cba6b1afb32b21bbde7166aafe5ecd3/pyinstrument-5.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:79a54def2d4aa83a4ed37c6cffc5494ae5de140f0453169eb4f7c744cc249d3a", size = 128268 }, { url = "https://files.pythonhosted.org/packages/0f/14/456f51598c2e8401b248c38591488c3815f38a4c0bca6babb3f81ab93a71/pyinstrument-5.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9538f746f166a40c8802ebe5c3e905d50f3faa189869cd71c083b8a639e574bb", size = 120299 }, { url = "https://files.pythonhosted.org/packages/11/e8/abeecedfa5dc6e6651e569c8876f0a55b973c906ebeb90185504a792ddb2/pyinstrument-5.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bbab65cae1483ad8a18429511d1eac9e3efec9f7961f2fd1bf90e1e2d69ef15", size = 143953 }, @@ -253,15 +238,6 @@ version = "6.0.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } wheels = [ - { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 }, - { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 }, - { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 }, - { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 }, - { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 }, - { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 }, - { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 }, - { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, - { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 }, { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 }, { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 },