{"id":13778937,"url":"https://github.com/xavdid/advent-of-code-python-template","last_synced_at":"2026-02-24T18:38:58.059Z","repository":{"id":197531504,"uuid":"698750065","full_name":"xavdid/advent-of-code-python-template","owner":"xavdid","description":"This is my tried-and-true Python helper for solving Advent of Code puzzles","archived":false,"fork":false,"pushed_at":"2024-11-30T19:27:51.000Z","size":36,"stargazers_count":22,"open_issues_count":0,"forks_count":6,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-23T17:08:54.168Z","etag":null,"topics":["advent-of-code","advent-of-code-starter","adventofcode","python","python3","template"],"latest_commit_sha":null,"homepage":"https://advent-of-code.xavd.id","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xavdid.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2023-09-30T21:06:06.000Z","updated_at":"2025-02-09T03:06:18.000Z","dependencies_parsed_at":"2024-01-15T18:46:04.935Z","dependency_job_id":"16ced98c-fb03-4113-88d3-d34815b6d9cf","html_url":"https://github.com/xavdid/advent-of-code-python-template","commit_stats":null,"previous_names":["xavdid/advent-of-code-python-template"],"tags_count":0,"template":true,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xavdid%2Fadvent-of-code-python-template","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xavdid%2Fadvent-of-code-python-template/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xavdid%2Fadvent-of-code-python-template/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xavdid%2Fadvent-of-code-python-template/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xavdid","download_url":"https://codeload.github.com/xavdid/advent-of-code-python-template/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250477812,"owners_count":21437049,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["advent-of-code","advent-of-code-starter","adventofcode","python","python3","template"],"created_at":"2024-08-03T18:00:59.171Z","updated_at":"2026-02-24T18:38:53.027Z","avatar_url":"https://github.com/xavdid.png","language":"Python","readme":"# @xavdid's Python Advent of Code Project Template\n\nThis is my tried-and-true Python utility package for the phenomenal [Advent of Code](https://adventofcode.com/) puzzles. It handles creating stub solutions, input parsing, and printing your answer, letting you focus on the actual solve. I've been [using it since 2017](https://github.com/xavdid/advent-of-code). It doesn't do _too_ much though- it doesn't pull or submit your input automatically, so no auth is required.\n\nAdditionally, Over in the main repo, I include a step-by-step [explanation of each puzzle](https://advent-of-code.xavd.id/) if you're in the learning mood!\n\n## Quickstart\n\nTo use this base class for your own solutions:\n\n1. Ensure you have Python `3.12` or higher. You can use [mise](https://mise.jdx.dev/) or [pyenv](https://github.com/pyenv/pyenv) to manage your Python versions. It may work on older versions, but `3.12`-specific features will be added without further breaking changes\n2. Create a new repo using this template ([docs](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template#creating-a-repository-from-a-template)) and clone it locally\n3. Start a new solution using `./start`\n4. Edit the newly created file at `solutions/YEAR/day_01/solution.py`\n5. Run your code answers using `./advent`\n6. Repeat and enjoy!\n\n## Commands\n\nThis repo has two main commands: `start` and `advent`.\n\n### `./start`\n\n#### Usage\n\n\u003e `./start [-h] [--year YEAR] [day]`\n\nScaffold files to start a new Advent of Code solution\n\n**positional arguments**:\n\n- `day` (optional): Which puzzle day to start, between `[1,25]`. Defaults to the next day _without_ a folder (matching `day_NN`) in the specified year.\n\n**optional arguments**:\n\n- `-h, --help` (optional): show this help message and exit\n- `--year YEAR` (optional): Puzzle year. Defaults to current year if December has begun, otherwise previous year.\n\n#### Examples\n\n- `./start`\n- `./start 2`\n- `./start 3 --year 2019`\n\n### `./advent`\n\n#### Usage\n\n\u003e `./advent [--year year] [--test-data] [--debug] [--profile] [--slow] [--time] [day]`\n\nRun a specific day of Advent of Code\n\n**informational flags**\n\n- `-h, --help`: Show this help message and exit\n- `--version`: Print version info and exit\n\n**positional arguments**:\n\n- `day` (optional): Which puzzle day to start, between `[1,25]`. Defaults to the latest day _with_ a folder (matching `day_NN`) in the specified year.\n\n**optional flags**:\n\n- `--year YEAR`: puzzle year. Defaults to current year if December has begun, otherwise previous year\n- `-t, --test-data`: read puzzle input from `input.test.txt` instead of `input.txt`. Ignores `@answer` decorators (see [saving answers](#saving-answers))\n- `--debug`: prints normally-hidden debugging statements (written with `self.debug(...)`). See [debugging](#debugging)\n- `--profile`: run solution through a performance profiler\n- `--slow`: specify that long-running solutions (or those requiring manual input) should be run. They're skipped otherwise\n- `--time`: print information about how long solutions took to run. More useful than timing at a shell level, since this only starts the timer once all imports have happened and any `advent`-related code is done.\n\n#### Examples\n\n- `./advent`\n- `./advent 2`\n- `./advent 5 --year 2019`\n- `./advent 7 --test-data`\n- `./advent 9 -t --debug`\n\n## File Structure\n\n\u003c!-- generated with https://tree.nathanfriend.io/ --\u003e\n\n```\nsolutions/\n├── ...\n└── 2020/\n    ├── day_01/\n    │   ├── solution.py\n    │   ├── input.txt\n    │   ├── input.test.txt\n    │   └── README.md\n    ├── day_02/\n    │   ├── solution.py\n    │   ├── ...\n    └── ...\n```\n\n- each year has a folder (`YYYY`)\n- each day in that year (will eventually) have a folder (`day_NN`)\n\nEach `day_NN` folder has the following files:\n\n- `solution.py`, which has a `class Solution`. `./advent` expects both that filename and that class name exactly, so you shouldn't change them. See [Writing Solutions](#writing-solutions) for how the file is structured\n- `input.txt` holds your individualized input from the AoC site. Make sure [not to share it publicly](https://old.reddit.com/r/adventofcode/wiki/troubleshooting/no_asking_for_inputs)!\n- `input.test.txt` holds the example input from the prompt. It's read when the `--test-input` flag is used (see below). It also won't throw errors if the result doesn't match the [answer](#saving-answers). You can also do all your work in `input.txt`, but it's marginally less convenient\n- `README.md` is a convenient place to take notes or explain your solution\n\n## Writing Solutions\n\n### The `Solution` Class\n\nA helpful base class on which to build your AoC solutions. It's got 2 required properties (which should be pre-filled if you use `./start`): `_year` and `_day`, corresponding to the puzzle you're solving.\n\nYour puzzle input, the parsed contents of the day's `input.txt`, will be available at `self.input`. Learn more in [Reading Input](#reading-input).\n\nThere's also a convenience method for print-based debugging: `self.debug()`. You can pass it any number of items and they'll get pretty-printed. It only prints if you use the `--debug` flag with `./advent`.\n\n### Reading Input\n\nAoC input takes a number of forms, so there are a number of simple modes for input parsing. Your generated `Solution` class should inherit from one of the following classes, which will parse `self.input` for you:\n\n| Inherited Class                  | description                                               | sample input for this mode |\n| -------------------------------- | --------------------------------------------------------- | -------------------------- |\n| `StrSplitSolution` (the default) | `str[]`, split by a specified separator (default newline) | a\u003cbr\u003eb\u003cbr\u003ec\u003cbr\u003ed\u003cbr\u003ee      |\n| `TextSolution`                   | one solid block of text                                   | `abcde`                    |\n| `IntSplitSolution`               | `int[]`, split by a specified separator (default newline) | 1\u003cbr\u003e2\u003cbr\u003e3\u003cbr\u003e4\u003cbr\u003e5      |\n| `IntSolution`                    | one number                                                | `12345`                    |\n\n```py\n# input file is \"12345\"\n\nfrom ...base import (\n    IntSolution,\n    IntSplitSolution,\n    StrSplitSolution,\n    TextSolution,\n)\n\nfor BaseClass in [TextSolution, IntSolution, StrSplitSolution, IntSplitSolution]:\n\n    class Solution(BaseClass):\n        def show_input(self):\n            print(f\"\\n{self.input} (type: {type(self.input)})\\n\")\n\n    Solution().show_input()\n\n# 12345 (type: \u003cclass 'str'\u003e)\n# 12345 (type: \u003cclass 'int'\u003e)\n# ['12345'] (type: \u003cclass 'list'\u003e)\n# [12345] (type: \u003cclass 'list'\u003e)\n```\n\nYou can also change the separator to change how the `SplitSolution`s work:\n\n```py\n# input file is \"1,2,3,4,5\"\n\nfrom ...base import IntSplitSolution, StrSplitSolution\n\nfor BaseClass in [StrSplitSolution, IntSplitSolution]:\n\n    class Solution(BaseClass):\n        separator = \",\"\n\n        def show_input(self):\n            print(f\"\\n{self.input} (type: {type(self.input)})\\n\")\n\n    Solution().show_input()\n\n# ['1', '2', '3', '4', '5'] (type: \u003cclass 'list'\u003e)\n# [1, 2, 3, 4, 5] (type: \u003cclass 'list'\u003e)\n```\n\n### Solution Functions\n\nEach AoC puzzle has two parts, so there are two functions you need to write: `part_1` and `part_2`. Each should return an `int`, since that's typically the answer that AoC expects.\n\nSometimes, it's easier to calculate both parts in a single function (such as if the answer is asking about two parts of a single computation). In that case, there's also a `solve()` method, which should return a 2-tuple with your answers (like `(5, 7)`). `solve` **takes precedence if present**. Feel free to delete any unused functions when you're done.\n\n```py\n\nclass Solution(TextSolution):\n    def part_1(self) -\u003e int:\n        return some_computation()\n\n    def part_2(self) -\u003e int:\n        return some_other_computation()\n\n    # or:\n\n    def solve(self) -\u003e tuple[int, int]:\n        part_1 = 0\n        total = 0\n\n        for i in range(10):\n            result = some_computation()\n            if i == 0:\n                part_1 = result\n\n            total += result\n\n        return result\n```\n\n### Saving Answers\n\nOnce you've solved the puzzle, you can decorate your answer function (`solve` or `part_N`) with the `@answer` decorator. It asserts that the value returned from the function is whatever you pass to the decorator:\n\n```py\nclass Solution(TextSolution):\n    _year = 2022\n    _day = 5\n\n    @answer(123)\n    def part_1(self) -\u003e int:\n        return 123\n\n    @answer(234)\n    def part_2(self) -\u003e int:\n        return 123 # err!\n```\n\nThis is helpful for ensuring your answer doesn't change when editing your code after you've solved the puzzle. It's included as a comment in the template. It's ignored when running against test input, so it's easy to verify as you go.\n\n### Debugging\n\nThe base class includes a `self.debug` method which will pretty-print all manner of inputs. These only show up when the `--debug` flag is used, making it a convenient way to show debugging info selectively.\n\n### Linting \u0026 Type Checking\n\nI recommend the following tools:\n\n- [Ruff](https://astral.sh/ruff), a lightning-fast linter (to help you catch bugs)\n- [Pyright](https://github.com/microsoft/pyright), a type checker to identify logical errors (also available in VSCode using their Python plugin)\n\nIf you have both available, then `just lint` will run them both. I've included a simple `ruff` configuration file to help get you started.\n\n### Marking Slow Solutions\n\nIf you're running many solutions at once and want to exclude individual parts of solutions (or entire days), you can mark individual functions with the `@slow` decorator. They'll print a warning, but won't actually run the solution.\n","funding_links":[],"categories":["Project Templates"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxavdid%2Fadvent-of-code-python-template","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxavdid%2Fadvent-of-code-python-template","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxavdid%2Fadvent-of-code-python-template/lists"}