mirror of
https://github.com/thib8956/advent-of-code.git
synced 2025-08-23 16:01:59 +00:00
chore: create new project structure and aoc.py runner script
This commit is contained in:
@@ -1,17 +0,0 @@
|
|||||||
ran day1/day1.py in 0.016s
|
|
||||||
ran day2/day2.py in 0.021s
|
|
||||||
ran day3/day3.py in 0.017s
|
|
||||||
ran day4/day4.py in 0.039s
|
|
||||||
ran day5/day5.py in 0.191s
|
|
||||||
ran day6/day6.py in 9.655s
|
|
||||||
ran day7/day7.py in 2.227s
|
|
||||||
ran day8/day8.py in 0.017s
|
|
||||||
ran day9/day9.py in 11.159s
|
|
||||||
ran day10/day10.py in 0.052s
|
|
||||||
ran day11/day11.py in 0.116s
|
|
||||||
ran day12/day12.py in 0.170s
|
|
||||||
ran day13/day13.py in 0.014s
|
|
||||||
ran day14/day14.py in 3.729s
|
|
||||||
ran day16/day16.py in 10.082s
|
|
||||||
ran day18/day18.py in 0.872s
|
|
||||||
|
|
26
Makefile
Normal file
26
Makefile
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
.PHONY: all venv install clean
|
||||||
|
|
||||||
|
# Define the virtual environment directory
|
||||||
|
VENV_DIR = ./venv
|
||||||
|
|
||||||
|
# Define the Python interpreter to use
|
||||||
|
PYTHON = $(VENV_DIR)/bin/python
|
||||||
|
|
||||||
|
# Default target
|
||||||
|
all: venv install
|
||||||
|
|
||||||
|
# Create virtual environment if it doesn't exist
|
||||||
|
venv:
|
||||||
|
@echo "Creating virtual environment..."
|
||||||
|
@if [ ! -d $(VENV_DIR) ]; then \
|
||||||
|
python3 -m venv $(VENV_DIR); \
|
||||||
|
fi
|
||||||
|
|
||||||
|
install: venv
|
||||||
|
@$(PYTHON) -m pip install --upgrade pip
|
||||||
|
@$(PYTHON) -m pip install -e .
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@echo "Removing virtual environment..."
|
||||||
|
@rm -rf $(VENV_DIR)
|
||||||
|
|
14
README.md
14
README.md
@@ -4,15 +4,25 @@ My solutions to the [advent of code](https://adventofcode.com/) challenges, writ
|
|||||||
|
|
||||||
## How to run
|
## How to run
|
||||||
|
|
||||||
|
### Install project
|
||||||
|
|
||||||
|
Run `make install` or
|
||||||
|
|
||||||
|
Run from root directory (inside a virtualenv):
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ pip install -e .
|
||||||
|
```
|
||||||
|
|
||||||
### Run a single day
|
### Run a single day
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ python3 run.py <year> <day>
|
$ aoc <year> <day>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Run a whole year
|
### Run a whole year
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ python3 run.py <year>
|
$ aoc <year>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
0
adventofcode/2019/__init__.py
Normal file
0
adventofcode/2019/__init__.py
Normal file
0
adventofcode/2019/day13/__init__.py
Normal file
0
adventofcode/2019/day13/__init__.py
Normal file
@@ -1,79 +1,79 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
|
||||||
def manhattan_distance(p):
|
def manhattan_distance(p):
|
||||||
return abs(p[0]) + abs(p[1])
|
return abs(p[0]) + abs(p[1])
|
||||||
|
|
||||||
|
|
||||||
def points_for_wire(wire):
|
def points_for_wire(wire):
|
||||||
x, y, count = 0, 0, 0
|
x, y, count = 0, 0, 0
|
||||||
points = {}
|
points = {}
|
||||||
# (x, y)
|
# (x, y)
|
||||||
directions = {"R": (1, 0), "L": (-1, 0), "U": (0, 1), "D": (0, -1)}
|
directions = {"R": (1, 0), "L": (-1, 0), "U": (0, 1), "D": (0, -1)}
|
||||||
for p in wire:
|
for p in wire:
|
||||||
# D42 -> for _ in range(42)
|
# D42 -> for _ in range(42)
|
||||||
for _ in range(int(p[1:])):
|
for _ in range(int(p[1:])):
|
||||||
offset = directions[p[0]]
|
offset = directions[p[0]]
|
||||||
x += offset[0]
|
x += offset[0]
|
||||||
y += offset[1]
|
y += offset[1]
|
||||||
count += 1
|
count += 1
|
||||||
points[(x ,y)] = count
|
points[(x ,y)] = count
|
||||||
|
|
||||||
return points
|
return points
|
||||||
|
|
||||||
|
|
||||||
def find_min_distance(wire1, wire2):
|
def find_min_distance(wire1, wire2):
|
||||||
points1 = points_for_wire(wire1)
|
points1 = points_for_wire(wire1)
|
||||||
points2 = points_for_wire(wire2)
|
points2 = points_for_wire(wire2)
|
||||||
|
|
||||||
intersections = points1.keys() & points2.keys()
|
intersections = points1.keys() & points2.keys()
|
||||||
closest = min((intersection for intersection in intersections), key=manhattan_distance)
|
closest = min((intersection for intersection in intersections), key=manhattan_distance)
|
||||||
|
|
||||||
return manhattan_distance(closest)
|
return manhattan_distance(closest)
|
||||||
|
|
||||||
|
|
||||||
def find_least_steps(wire1, wire2):
|
def find_least_steps(wire1, wire2):
|
||||||
points1 = points_for_wire(wire1)
|
points1 = points_for_wire(wire1)
|
||||||
points2 = points_for_wire(wire2)
|
points2 = points_for_wire(wire2)
|
||||||
|
|
||||||
intersections = points1.keys() & points2.keys()
|
intersections = points1.keys() & points2.keys()
|
||||||
# Intersection with the least steps
|
# Intersection with the least steps
|
||||||
least_steps = min(intersections, key=lambda x: points1[x] + points2[x])
|
least_steps = min(intersections, key=lambda x: points1[x] + points2[x])
|
||||||
|
|
||||||
return points1[least_steps] + points2[least_steps]
|
return points1[least_steps] + points2[least_steps]
|
||||||
|
|
||||||
|
|
||||||
def tests():
|
def tests():
|
||||||
inputs = (
|
inputs = (
|
||||||
(("R8", "U5", "L5", "D3"), ("U7", "R6", "D4", "L4")),
|
(("R8", "U5", "L5", "D3"), ("U7", "R6", "D4", "L4")),
|
||||||
(("R75","D30","R83", "U83", "L12", "D49", "R71", "U7", "L72"), ("U62", "R66", "U55", "R34", "D71", "R55", "D58", "R83")),
|
(("R75","D30","R83", "U83", "L12", "D49", "R71", "U7", "L72"), ("U62", "R66", "U55", "R34", "D71", "R55", "D58", "R83")),
|
||||||
(("R98", "U47", "R26", "D63", "R33", "U87", "L62", "D20", "R33", "U53", "R51"), ("U98", "R91", "D20", "R16", "D67", "R40", "U7", "R15", "U6", "R7"))
|
(("R98", "U47", "R26", "D63", "R33", "U87", "L62", "D20", "R33", "U53", "R51"), ("U98", "R91", "D20", "R16", "D67", "R40", "U7", "R15", "U6", "R7"))
|
||||||
)
|
)
|
||||||
|
|
||||||
# Part 1
|
# Part 1
|
||||||
expected = (6, 159, 135)
|
expected = (6, 159, 135)
|
||||||
for i, inp in enumerate(inputs):
|
for i, inp in enumerate(inputs):
|
||||||
result = find_min_distance(inp[0], inp[1])
|
result = find_min_distance(inp[0], inp[1])
|
||||||
assert result == expected[i], "Result for {} should be {}, was {}".format(
|
assert result == expected[i], "Result for {} should be {}, was {}".format(
|
||||||
inp, expected[i], result
|
inp, expected[i], result
|
||||||
)
|
)
|
||||||
|
|
||||||
# Part 2
|
# Part 2
|
||||||
# expected number of steps
|
# expected number of steps
|
||||||
expected_part2 = (30, 610, 410)
|
expected_part2 = (30, 610, 410)
|
||||||
print("All tests passed.")
|
print("All tests passed.")
|
||||||
for i, inp in enumerate(inputs):
|
for i, inp in enumerate(inputs):
|
||||||
result = find_least_steps(inp[0], inp[1])
|
result = find_least_steps(inp[0], inp[1])
|
||||||
assert result == expected_part2[i], "Result for {} should be {}, was {}".format(
|
assert result == expected_part2[i], "Result for {} should be {}, was {}".format(
|
||||||
inp, expected_part2[i], result
|
inp, expected_part2[i], result
|
||||||
)
|
)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
tests()
|
tests()
|
||||||
import sys
|
import sys
|
||||||
infile = sys.argv[1] if len(sys.argv) > 1 else "example.txt"
|
infile = sys.argv[1] if len(sys.argv) > 1 else "example.txt"
|
||||||
with open(infile) as raw_input:
|
with open(infile) as raw_input:
|
||||||
lines = raw_input.readlines()
|
lines = raw_input.readlines()
|
||||||
wire1, wire2 = [line.strip("\n").split(",") for line in lines]
|
wire1, wire2 = [line.strip("\n").split(",") for line in lines]
|
||||||
print("Part 1 -- distance = ", find_min_distance(wire1, wire2))
|
print("Part 1 -- distance = ", find_min_distance(wire1, wire2))
|
||||||
print("Part 2 -- steps = ", find_least_steps(wire1, wire2))
|
print("Part 2 -- steps = ", find_least_steps(wire1, wire2))
|
@@ -1,14 +1,11 @@
|
|||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
# TODO replace PYTHONPATH hack with a proper solution, like making intcode an
|
|
||||||
# installed module https://stackoverflow.com/a/50194143
|
|
||||||
sys.path.append(str(Path(__file__).absolute().parent.parent / "intcode"))
|
sys.path.append(str(Path(__file__).absolute().parent.parent / "intcode"))
|
||||||
|
|
||||||
from itertools import cycle, permutations
|
from itertools import cycle, permutations
|
||||||
from intcode import interpret_intcode, Interpreter
|
from intcode import interpret_intcode, Interpreter
|
||||||
|
|
||||||
|
|
||||||
def main(inp):
|
def main(inp):
|
||||||
mem = list(map(int, inp.readline().rstrip().split(",")))
|
mem = list(map(int, inp.readline().rstrip().split(",")))
|
||||||
max_ret = 0
|
max_ret = 0
|
41
adventofcode/aoc.py
Normal file
41
adventofcode/aoc.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import argparse
|
||||||
|
from adventofcode.helper import run, get_input_file
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Advent of Code CLI")
|
||||||
|
subparsers = parser.add_subparsers(dest='command')
|
||||||
|
|
||||||
|
# Sous-commande init
|
||||||
|
init_parser = subparsers.add_parser('init', help='Init an aoc day')
|
||||||
|
init_parser.add_argument('year', type=int)
|
||||||
|
init_parser.add_argument('day', type=int)
|
||||||
|
|
||||||
|
# Sous-commande run
|
||||||
|
run_parser = subparsers.add_parser('run', help='Run an aoc day')
|
||||||
|
run_parser.add_argument('year', type=int)
|
||||||
|
run_parser.add_argument('day', type=int)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.command == 'init':
|
||||||
|
handle_init(args.year, args.day)
|
||||||
|
elif args.command == 'run':
|
||||||
|
handle_run(args.year, args.day)
|
||||||
|
else:
|
||||||
|
parser.print_help()
|
||||||
|
|
||||||
|
|
||||||
|
def handle_init(year, day):
|
||||||
|
# TODO initialize directory if needed, download input file and create
|
||||||
|
# dayX.py from a template
|
||||||
|
raise NotImplementedError("init")
|
||||||
|
|
||||||
|
|
||||||
|
def handle_run(year, day):
|
||||||
|
run(year, day)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
@@ -1,3 +1,4 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import getpass
|
import getpass
|
||||||
import sys
|
import sys
|
||||||
@@ -6,6 +7,7 @@ import subprocess
|
|||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOTPATH = Path(os.path.dirname(os.path.realpath(__file__)))
|
||||||
|
|
||||||
_auth = None
|
_auth = None
|
||||||
|
|
||||||
@@ -27,9 +29,9 @@ def get_input_file(year, day):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
def main(year, day):
|
def run(year, day):
|
||||||
if day is not None:
|
if day is not None:
|
||||||
path = Path(f"{year}/day{day}")
|
path = ROOTPATH / Path(f"{year}/day{day}")
|
||||||
script_path = path / Path(f"day{day}.py")
|
script_path = path / Path(f"day{day}.py")
|
||||||
input_path = path / Path("input.txt")
|
input_path = path / Path("input.txt")
|
||||||
if not script_path.exists():
|
if not script_path.exists():
|
||||||
@@ -45,7 +47,7 @@ def main(year, day):
|
|||||||
run_day(script_path, input_path)
|
run_day(script_path, input_path)
|
||||||
else:
|
else:
|
||||||
for day in range(1, 26):
|
for day in range(1, 26):
|
||||||
path = Path(f"{year}/day{day}")
|
path = ROOTPATH / Path(f"{year}/day{day}")
|
||||||
script_path = path / Path(f"day{day}.py")
|
script_path = path / Path(f"day{day}.py")
|
||||||
input_path = path / Path("input.txt")
|
input_path = path / Path("input.txt")
|
||||||
if script_path.exists():
|
if script_path.exists():
|
||||||
@@ -69,12 +71,3 @@ def run_day(script_path, input_path):
|
|||||||
except subprocess.TimeoutExpired:
|
except subprocess.TimeoutExpired:
|
||||||
print(f"> timeout {script_path} after 30s", file=sys.stderr)
|
print(f"> timeout {script_path} after 30s", file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
if len(sys.argv) <= 1:
|
|
||||||
print(f"Usage: {__file__} <year> [<day>]", file=sys.stderr)
|
|
||||||
exit(1)
|
|
||||||
year = sys.argv[1]
|
|
||||||
day = sys.argv[2] if len(sys.argv) > 2 else None
|
|
||||||
main(year, day)
|
|
||||||
|
|
14
pyproject.toml
Normal file
14
pyproject.toml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "adventofcode"
|
||||||
|
version = "1.0.0"
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
aoc = "adventofcode.aoc:main"
|
||||||
|
|
||||||
|
[tool.setuptools.packages.find]
|
||||||
|
where = ["."]
|
||||||
|
|
Reference in New Issue
Block a user