add day 2

This commit is contained in:
Moritz Böhme 2022-12-02 10:18:10 +01:00
parent ca4c02a1e7
commit bbefd598a9
Signed by: moritz
GPG key ID: 970C6E89EB0547A9
6 changed files with 2857 additions and 9 deletions

177
.gitignore vendored Normal file
View file

@ -0,0 +1,177 @@
# Created by https://www.toptal.com/developers/gitignore/api/direnv,python
# Edit at https://www.toptal.com/developers/gitignore?templates=direnv,python
### direnv ###
.direnv
.envrc
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
### Python Patch ###
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
poetry.toml
# End of https://www.toptal.com/developers/gitignore/api/direnv,python
.pre-commit-config.yaml

76
2022/poetry.lock generated
View file

@ -16,7 +16,7 @@ tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy
name = "black"
version = "22.10.0"
description = "The uncompromising code formatter."
category = "main"
category = "dev"
optional = false
python-versions = ">=3.7"
@ -36,7 +36,7 @@ uvloop = ["uvloop (>=0.15.2)"]
name = "click"
version = "8.1.3"
description = "Composable command line interface toolkit"
category = "main"
category = "dev"
optional = false
python-versions = ">=3.7"
@ -47,7 +47,7 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""}
name = "colorama"
version = "0.4.6"
description = "Cross-platform colored terminal text."
category = "main"
category = "dev"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
@ -59,11 +59,29 @@ category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "mypy"
version = "0.991"
description = "Optional static typing for Python"
category = "dev"
optional = false
python-versions = ">=3.7"
[package.dependencies]
mypy-extensions = ">=0.4.3"
typing-extensions = ">=3.10"
[package.extras]
dmypy = ["psutil (>=4.0)"]
install-types = ["pip"]
python2 = ["typed-ast (>=1.4.0,<2)"]
reports = ["lxml"]
[[package]]
name = "mypy-extensions"
version = "0.4.3"
description = "Experimental type system extensions for programs checked with the mypy typechecker."
category = "main"
category = "dev"
optional = false
python-versions = "*"
@ -82,7 +100,7 @@ pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
name = "pathspec"
version = "0.10.2"
description = "Utility library for gitignore style pattern matching of file paths."
category = "main"
category = "dev"
optional = false
python-versions = ">=3.7"
@ -90,7 +108,7 @@ python-versions = ">=3.7"
name = "platformdirs"
version = "2.5.4"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
category = "main"
category = "dev"
optional = false
python-versions = ">=3.7"
@ -139,10 +157,18 @@ pluggy = ">=0.12,<2.0"
[package.extras]
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
[[package]]
name = "typing-extensions"
version = "4.4.0"
description = "Backported and Experimental Type Hints for Python 3.7+"
category = "dev"
optional = false
python-versions = ">=3.7"
[metadata]
lock-version = "1.1"
python-versions = "^3.11"
content-hash = "adba8c1dd6be494968ab1869bbb1735cfffa6e28fbe981d0d0299faba66d48f9"
content-hash = "aa5f7acd6a56ea1b59655b53695bba33c3970e6f62b319f8cfc1f5d3734fe13d"
[metadata.files]
attrs = [
@ -184,6 +210,38 @@ iniconfig = [
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
]
mypy = [
{file = "mypy-0.991-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7d17e0a9707d0772f4a7b878f04b4fd11f6f5bcb9b3813975a9b13c9332153ab"},
{file = "mypy-0.991-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0714258640194d75677e86c786e80ccf294972cc76885d3ebbb560f11db0003d"},
{file = "mypy-0.991-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c8f3be99e8a8bd403caa8c03be619544bc2c77a7093685dcf308c6b109426c6"},
{file = "mypy-0.991-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc9ec663ed6c8f15f4ae9d3c04c989b744436c16d26580eaa760ae9dd5d662eb"},
{file = "mypy-0.991-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4307270436fd7694b41f913eb09210faff27ea4979ecbcd849e57d2da2f65305"},
{file = "mypy-0.991-cp310-cp310-win_amd64.whl", hash = "sha256:901c2c269c616e6cb0998b33d4adbb4a6af0ac4ce5cd078afd7bc95830e62c1c"},
{file = "mypy-0.991-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d13674f3fb73805ba0c45eb6c0c3053d218aa1f7abead6e446d474529aafc372"},
{file = "mypy-0.991-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1c8cd4fb70e8584ca1ed5805cbc7c017a3d1a29fb450621089ffed3e99d1857f"},
{file = "mypy-0.991-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:209ee89fbb0deed518605edddd234af80506aec932ad28d73c08f1400ef80a33"},
{file = "mypy-0.991-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37bd02ebf9d10e05b00d71302d2c2e6ca333e6c2a8584a98c00e038db8121f05"},
{file = "mypy-0.991-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:26efb2fcc6b67e4d5a55561f39176821d2adf88f2745ddc72751b7890f3194ad"},
{file = "mypy-0.991-cp311-cp311-win_amd64.whl", hash = "sha256:3a700330b567114b673cf8ee7388e949f843b356a73b5ab22dd7cff4742a5297"},
{file = "mypy-0.991-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1f7d1a520373e2272b10796c3ff721ea1a0712288cafaa95931e66aa15798813"},
{file = "mypy-0.991-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:641411733b127c3e0dab94c45af15fea99e4468f99ac88b39efb1ad677da5711"},
{file = "mypy-0.991-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3d80e36b7d7a9259b740be6d8d906221789b0d836201af4234093cae89ced0cd"},
{file = "mypy-0.991-cp37-cp37m-win_amd64.whl", hash = "sha256:e62ebaad93be3ad1a828a11e90f0e76f15449371ffeecca4a0a0b9adc99abcef"},
{file = "mypy-0.991-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b86ce2c1866a748c0f6faca5232059f881cda6dda2a893b9a8373353cfe3715a"},
{file = "mypy-0.991-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac6e503823143464538efda0e8e356d871557ef60ccd38f8824a4257acc18d93"},
{file = "mypy-0.991-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0cca5adf694af539aeaa6ac633a7afe9bbd760df9d31be55ab780b77ab5ae8bf"},
{file = "mypy-0.991-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a12c56bf73cdab116df96e4ff39610b92a348cc99a1307e1da3c3768bbb5b135"},
{file = "mypy-0.991-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:652b651d42f155033a1967739788c436491b577b6a44e4c39fb340d0ee7f0d70"},
{file = "mypy-0.991-cp38-cp38-win_amd64.whl", hash = "sha256:4175593dc25d9da12f7de8de873a33f9b2b8bdb4e827a7cae952e5b1a342e243"},
{file = "mypy-0.991-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:98e781cd35c0acf33eb0295e8b9c55cdbef64fcb35f6d3aa2186f289bed6e80d"},
{file = "mypy-0.991-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6d7464bac72a85cb3491c7e92b5b62f3dcccb8af26826257760a552a5e244aa5"},
{file = "mypy-0.991-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c9166b3f81a10cdf9b49f2d594b21b31adadb3d5e9db9b834866c3258b695be3"},
{file = "mypy-0.991-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8472f736a5bfb159a5e36740847808f6f5b659960115ff29c7cecec1741c648"},
{file = "mypy-0.991-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e80e758243b97b618cdf22004beb09e8a2de1af481382e4d84bc52152d1c476"},
{file = "mypy-0.991-cp39-cp39-win_amd64.whl", hash = "sha256:74e259b5c19f70d35fcc1ad3d56499065c601dfe94ff67ae48b85596b9ec1461"},
{file = "mypy-0.991-py3-none-any.whl", hash = "sha256:de32edc9b0a7e67c2775e574cb061a537660e51210fbf6006b0b36ea695ae9bb"},
{file = "mypy-0.991.tar.gz", hash = "sha256:3c0165ba8f354a6d9881809ef29f1a9318a236a6d81c690094c5df32107bde06"},
]
mypy-extensions = [
{file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
@ -212,3 +270,7 @@ pytest = [
{file = "pytest-7.2.0-py3-none-any.whl", hash = "sha256:892f933d339f068883b6fd5a459f03d85bfcb355e4981e146d2c7616c21fef71"},
{file = "pytest-7.2.0.tar.gz", hash = "sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59"},
]
typing-extensions = [
{file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"},
{file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"},
]

View file

@ -9,10 +9,12 @@ packages = [
[tool.poetry.dependencies]
python = "^3.11"
black = "^22.10.0"
[tool.poetry.group.dev.dependencies]
pytest = "^7.2.0"
black = "^22.10.0"
mypy = "^0.991"
[build-system]
requires = ["poetry-core"]

View file

@ -1,6 +1,6 @@
from first import sum_blocks
from second import main, maximum
from test_first import blocks, example
from first import sum_blocks
def test_maximum(blocks):

2500
2022/src/day2/input.txt Normal file

File diff suppressed because it is too large Load diff

107
2022/src/day2/solution.py Normal file
View file

@ -0,0 +1,107 @@
import enum
import logging
from typing import Self
logger = logging.getLogger(__name__)
class Shape(enum.Enum):
ROCK = enum.auto()
PAPER = enum.auto()
SCISSORS = enum.auto()
@classmethod
def from_theirs(cls, letter: str) -> Self:
mapping = {"A": cls.ROCK, "B": cls.PAPER, "C": cls.SCISSORS}
return mapping[letter]
@classmethod
def from_ours(cls, letter: str) -> Self:
mapping = {"X": cls.ROCK, "Y": cls.PAPER, "Z": cls.SCISSORS}
return mapping[letter]
def parse_input_part1(lines: list[str]) -> list[tuple[Shape, Shape]]:
rounds = []
for line in lines:
try:
theirs, ours = line.strip().split(maxsplit=1)
rounds.append((Shape.from_theirs(theirs), Shape.from_ours(ours)))
except Exception:
logger.warning(f"Could not parse the line '{line}'!")
return rounds
class RoundOutcome(enum.Enum):
LOSE = enum.auto()
DRAW = enum.auto()
WIN = enum.auto()
@classmethod
def from_xyz(cls, letter: str) -> Self:
mapping = {
"X": cls.LOSE,
"Y": cls.DRAW,
"Z": cls.WIN,
}
return mapping[letter]
def compute_round_outcome(theirs: Shape, ours: Shape) -> RoundOutcome:
if theirs == ours:
return RoundOutcome.DRAW
win_scenarios = [
(Shape.ROCK, Shape.PAPER),
(Shape.PAPER, Shape.SCISSORS),
(Shape.SCISSORS, Shape.ROCK),
]
if (theirs, ours) in win_scenarios:
return RoundOutcome.WIN
else:
return RoundOutcome.LOSE
def compute_round_score(theirs: Shape, ours: Shape) -> int:
shape_value = {Shape.ROCK: 1, Shape.PAPER: 2, Shape.SCISSORS: 3}
round_outcome = compute_round_outcome(theirs, ours)
round_value = {RoundOutcome.LOSE: 0, RoundOutcome.DRAW: 3, RoundOutcome.WIN: 6}
return shape_value[ours] + round_value[round_outcome]
def part1(lines: list[str]) -> int:
rounds = parse_input_part1(lines)
return sum(compute_round_score(*round_shapes) for round_shapes in rounds)
def parse_input_part2(lines: list[str]) -> list[tuple[Shape, RoundOutcome]]:
rounds = []
for line in lines:
try:
theirs, outcome = line.strip().split(maxsplit=1)
rounds.append((Shape.from_theirs(theirs), RoundOutcome.from_xyz(outcome)))
except Exception:
logger.warning(f"Could not parse the line '{line}'!")
return rounds
def choose_shape(theirs: Shape, outcome: RoundOutcome) -> Shape:
for shape in Shape:
if compute_round_outcome(theirs, shape) == outcome:
return shape
raise RuntimeError(f"No winning shape found for {(theirs, outcome)}!")
def part2(lines: list[str]) -> int:
rounds = parse_input_part2(lines)
return sum(
compute_round_score(theirs, choose_shape(theirs, outcome))
for theirs, outcome in rounds
)
if __name__ == "__main__":
with open("input.txt") as file:
contents = file.readlines()
print(f"Solution 1: {part1(contents)}")
print(f"Solution 2: {part2(contents)}")