mirror of
https://github.com/thib8956/advent-of-code.git
synced 2026-11-06 10:02:27 +00:00
chore: create new project structure and aoc.py runner script
This commit is contained in:
1 parent
f76375d835
commit
e2964c6c36
91 files changed
+177
-113
No files matched your search
@@ -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
|
|
||||||
|
|
||||||
@@ -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)
|
||||||
|
|
||||||
@@ -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>
|
||||||
```
|
```
|
||||||
|
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Whitespace-only changes.
File renamed without changes.
File renamed without changes.
Whitespace-only changes.
File renamed without changes.
File renamed without changes.
@@ -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))
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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)
|
|
||||||
|
|
||||||
@@ -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